summaryrefslogtreecommitdiff
path: root/platform/darwin
diff options
context:
space:
mode:
Diffstat (limited to 'platform/darwin')
-rw-r--r--platform/darwin/docs/guides/For Style Authors.md.ejs10
-rw-r--r--platform/darwin/scripts/generate-style-code.js14
-rw-r--r--platform/darwin/src/MGLCircleStyleLayer.h45
-rw-r--r--platform/darwin/src/MGLCircleStyleLayer.mm32
-rw-r--r--platform/darwin/src/MGLConversion.h8
-rw-r--r--platform/darwin/src/MGLGeometry.h54
-rw-r--r--platform/darwin/src/MGLGeometry_Private.h15
-rw-r--r--platform/darwin/src/MGLImageSource.h94
-rw-r--r--platform/darwin/src/MGLImageSource.mm92
-rw-r--r--platform/darwin/src/MGLLight.h2
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.h23
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.mm12
-rw-r--r--platform/darwin/src/MGLMapSnapshotter.h105
-rw-r--r--platform/darwin/src/MGLMapSnapshotter.mm163
-rw-r--r--platform/darwin/src/MGLMultiPoint.mm2
-rw-r--r--platform/darwin/src/MGLOfflineStorage.h2
-rw-r--r--platform/darwin/src/MGLOfflineStorage.mm20
-rw-r--r--platform/darwin/src/MGLOpenGLStyleLayer.h3
-rw-r--r--platform/darwin/src/MGLOpenGLStyleLayer.mm37
-rw-r--r--platform/darwin/src/MGLRendererFrontend.h70
-rw-r--r--platform/darwin/src/MGLShapeSource.mm4
-rw-r--r--platform/darwin/src/MGLSource.h2
-rw-r--r--platform/darwin/src/MGLSource.mm12
-rw-r--r--platform/darwin/src/MGLSource_Private.h3
-rw-r--r--platform/darwin/src/MGLStyle.h85
-rw-r--r--platform/darwin/src/MGLStyle.mm116
-rw-r--r--platform/darwin/src/MGLStyleLayer.mm18
-rw-r--r--platform/darwin/src/MGLStyleLayer_Private.h6
-rw-r--r--platform/darwin/src/MGLStyle_Private.h9
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.h190
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.mm96
-rw-r--r--platform/darwin/src/MGLVectorSource.mm4
-rw-r--r--platform/darwin/src/NSValue+MGLAdditions.h14
-rw-r--r--platform/darwin/src/NSValue+MGLAdditions.m10
-rw-r--r--platform/darwin/src/headless_backend_cgl.cpp2
-rw-r--r--platform/darwin/src/http_file_source.mm4
-rw-r--r--platform/darwin/src/nsthread.mm3
-rw-r--r--platform/darwin/src/run_loop.cpp20
-rw-r--r--platform/darwin/test/MGLCircleStyleLayerTests.mm42
-rw-r--r--platform/darwin/test/MGLDocumentationExampleTests.swift14
-rw-r--r--platform/darwin/test/MGLGeometryTests.mm19
-rw-r--r--platform/darwin/test/MGLImageSourceTests.m42
-rw-r--r--platform/darwin/test/MGLLightTest.mm20
-rw-r--r--platform/darwin/test/MGLLightTest.mm.ejs10
-rw-r--r--platform/darwin/test/MGLLineStyleLayerTests.mm37
-rw-r--r--platform/darwin/test/MGLStyleTests.mm18
-rw-r--r--platform/darwin/test/MGLSymbolStyleLayerTests.mm165
-rw-r--r--platform/darwin/test/Media.xcassets/RadarImage.imageset/Contents.json21
-rw-r--r--platform/darwin/test/Media.xcassets/RadarImage.imageset/radar.pngbin0 -> 44094 bytes
49 files changed, 1488 insertions, 301 deletions
diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs
index 26c533632f..06a8907704 100644
--- a/platform/darwin/docs/guides/For Style Authors.md.ejs
+++ b/platform/darwin/docs/guides/For Style Authors.md.ejs
@@ -160,7 +160,6 @@ the following terms for concepts defined in the style specification:
In the style specification | In the SDK
---------------------------|---------
-class | style class
filter | predicate
function type | interpolation mode
id | identifier
@@ -181,8 +180,9 @@ In style JSON | In the SDK
`geojson` | `MGLShapeSource`
`raster` | `MGLRasterSource`
`vector` | `MGLVectorSource`
+`image` | `MGLImageSource`
-`canvas`, `image`, and `video` sources are not supported.
+`canvas` and `video` sources are not supported.
### Tile sources
@@ -223,6 +223,12 @@ To create a shape source from local GeoJSON data, first
[convert the GeoJSON data into a shape](working-with-geojson-data.html#converting-geojson-data-into-shape-objects),
then use the `-[MGLShapeSource initWithIdentifier:shape:options:]` method.
+### Image sources
+
+Image sources accept a non-axis aligned quadrilateral as their geographic coordinates.
+These coordinates, in `MGLCoordinateQuad`, are described in counterclockwise order,
+in contrast to the clockwise order defined in the style specification.
+
## Configuring the map content’s appearance
Each layer defined by the style JSON file is represented at runtime by a style
diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js
index 5a4936c0ee..4ee86e65da 100644
--- a/platform/darwin/scripts/generate-style-code.js
+++ b/platform/darwin/scripts/generate-style-code.js
@@ -148,6 +148,9 @@ global.mbglTestValue = function (property, layerType) {
if (/-(rotation|pitch)-alignment$/.test(originalPropertyName(property))) {
type = 'Alignment';
}
+ if (/^(text|icon)-anchor$/.test(originalPropertyName(property))) {
+ type = 'SymbolAnchor'
+ }
let value = camelize(_.last(_.keys(property.values)));
if (property['light-property']) {
return `mbgl::style::Light${type}Type::${value}`;
@@ -500,6 +503,9 @@ global.mbglType = function(property) {
if (/-(rotation|pitch)-alignment$/.test(originalPropertyName(property))) {
type = 'Alignment';
}
+ if (/^(text|icon)-anchor$/.test(originalPropertyName(property))) {
+ type = 'SymbolAnchor'
+ }
return `mbgl::style::${type}Type`;
}
case 'color':
@@ -648,10 +654,10 @@ while ((match = exampleRegex.exec(examplesSrc)) !== null) {
let testMethodName = match[1],
indentation = match[2],
exampleCode = match[3];
-
+
// Trim leading whitespace from the example code.
exampleCode = exampleCode.replace(new RegExp('^' + indentation, 'gm'), '');
-
+
examples[testMethodName] = exampleCode;
}
@@ -663,13 +669,13 @@ global.guideExample = function (guide, exampleId, os) {
console.error(`MGLDocumentationExampleTests.test${testMethodName}() not found.`);
process.exit(1);
}
-
+
// Resolve conditional compilation blocks.
example = example.replace(/^(\s*)#if\s+os\((iOS|macOS)\)\n([^]*?)(?:^\1#else\n([^]*?))?^\1#endif\b\n?/gm,
function (m, indentation, ifOs, ifCase, elseCase) {
return (os === ifOs ? ifCase : elseCase).replace(new RegExp('^ ', 'gm'), '');
}).replace(/\n$/, '');
-
+
return '```swift\n' + example + '\n```';
};
diff --git a/platform/darwin/src/MGLCircleStyleLayer.h b/platform/darwin/src/MGLCircleStyleLayer.h
index 789ff7a258..ea95f6beef 100644
--- a/platform/darwin/src/MGLCircleStyleLayer.h
+++ b/platform/darwin/src/MGLCircleStyleLayer.h
@@ -8,6 +8,23 @@
NS_ASSUME_NONNULL_BEGIN
/**
+ Orientation of circle when map is pitched.
+
+ Values of this type are used in the `MGLCircleStyleLayer.circlePitchAlignment`
+ property.
+ */
+typedef NS_ENUM(NSUInteger, MGLCirclePitchAlignment) {
+ /**
+ The circle is aligned to the plane of the map.
+ */
+ MGLCirclePitchAlignmentMap,
+ /**
+ The circle is aligned to the plane of the viewport.
+ */
+ MGLCirclePitchAlignmentViewport,
+};
+
+/**
Controls the scaling behavior of the circle when the map is pitched.
Values of this type are used in the `MGLCircleStyleLayer.circleScaleAlignment`
@@ -221,6 +238,21 @@ MGL_EXPORT
@property (nonatomic) MGLTransition circleOpacityTransition;
/**
+ Orientation of circle when map is pitched.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLCirclePitchAlignmentViewport`. Set this
+ property to `nil` to reset it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLConstantStyleValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circlePitchAlignment;
+
+/**
Circle radius.
This property is measured in points.
@@ -491,6 +523,19 @@ MGL_EXPORT
#pragma mark Working with Circle Style Layer Attribute Values
/**
+ Creates a new value object containing the given `MGLCirclePitchAlignment` enumeration.
+
+ @param circlePitchAlignment The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLCirclePitchAlignment:(MGLCirclePitchAlignment)circlePitchAlignment;
+
+/**
+ The `MGLCirclePitchAlignment` enumeration representation of the value.
+ */
+@property (readonly) MGLCirclePitchAlignment MGLCirclePitchAlignmentValue;
+
+/**
Creates a new value object containing the given `MGLCircleScaleAlignment` enumeration.
@param circleScaleAlignment The value for the new object.
diff --git a/platform/darwin/src/MGLCircleStyleLayer.mm b/platform/darwin/src/MGLCircleStyleLayer.mm
index 42961f2e12..71ae37035e 100644
--- a/platform/darwin/src/MGLCircleStyleLayer.mm
+++ b/platform/darwin/src/MGLCircleStyleLayer.mm
@@ -13,6 +13,11 @@
namespace mbgl {
+ MBGL_DEFINE_ENUM(MGLCirclePitchAlignment, {
+ { MGLCirclePitchAlignmentMap, "map" },
+ { MGLCirclePitchAlignmentViewport, "viewport" },
+ });
+
MBGL_DEFINE_ENUM(MGLCircleScaleAlignment, {
{ MGLCircleScaleAlignmentMap, "map" },
{ MGLCircleScaleAlignmentViewport, "viewport" },
@@ -187,6 +192,23 @@ namespace mbgl {
return transition;
}
+- (void)setCirclePitchAlignment:(MGLStyleValue<NSValue *> *)circlePitchAlignment {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLCirclePitchAlignment>().toEnumPropertyValue(circlePitchAlignment);
+ self.rawLayer->setCirclePitchAlignment(mbglValue);
+}
+
+- (MGLStyleValue<NSValue *> *)circlePitchAlignment {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getCirclePitchAlignment();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLCirclePitchAlignment>().toEnumStyleValue(self.rawLayer->getDefaultCirclePitchAlignment());
+ }
+ return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLCirclePitchAlignment>().toEnumStyleValue(propertyValue);
+}
+
- (void)setCircleRadius:(MGLStyleValue<NSNumber *> *)circleRadius {
MGLAssertStyleLayerIsValid();
@@ -421,6 +443,16 @@ namespace mbgl {
@implementation NSValue (MGLCircleStyleLayerAdditions)
++ (NSValue *)valueWithMGLCirclePitchAlignment:(MGLCirclePitchAlignment)circlePitchAlignment {
+ return [NSValue value:&circlePitchAlignment withObjCType:@encode(MGLCirclePitchAlignment)];
+}
+
+- (MGLCirclePitchAlignment)MGLCirclePitchAlignmentValue {
+ MGLCirclePitchAlignment circlePitchAlignment;
+ [self getValue:&circlePitchAlignment];
+ return circlePitchAlignment;
+}
+
+ (NSValue *)valueWithMGLCircleScaleAlignment:(MGLCircleScaleAlignment)circleScaleAlignment {
return [NSValue value:&circleScaleAlignment withObjCType:@encode(MGLCircleScaleAlignment)];
}
diff --git a/platform/darwin/src/MGLConversion.h b/platform/darwin/src/MGLConversion.h
index d51ebd775c..d6363b28eb 100644
--- a/platform/darwin/src/MGLConversion.h
+++ b/platform/darwin/src/MGLConversion.h
@@ -104,6 +104,14 @@ inline optional<float> toNumber(const id value) {
}
}
+inline optional<double> toDouble(const id value) {
+ if (_isNumber(value)) {
+ return ((NSNumber *)value).doubleValue;
+ } else {
+ return {};
+ }
+}
+
inline optional<std::string> toString(const id value) {
if (_isString(value)) {
return std::string(static_cast<const char *>([value UTF8String]));
diff --git a/platform/darwin/src/MGLGeometry.h b/platform/darwin/src/MGLGeometry.h
index d37741cde5..7c68033abf 100644
--- a/platform/darwin/src/MGLGeometry.h
+++ b/platform/darwin/src/MGLGeometry.h
@@ -45,6 +45,24 @@ typedef struct __attribute__((objc_boxable)) MGLCoordinateBounds {
CLLocationCoordinate2D ne;
} MGLCoordinateBounds;
+/**
+ A quadrilateral area as measured on a two-dimensional map projection.
+ `MGLCoordinateQuad` differs from `MGLCoordinateBounds` in that it allows
+ representation of non-axis aligned bounds and non-rectangular quadrilaterals.
+ The coordinates are described in counter clockwise order from top left.
+ */
+typedef struct MGLCoordinateQuad {
+ /** Coordinate at the top left corner. */
+ CLLocationCoordinate2D topLeft;
+ /** Coordinate at the bottom left corner. */
+ CLLocationCoordinate2D bottomLeft;
+ /** Coordinate at the bottom right corner. */
+ CLLocationCoordinate2D bottomRight;
+ /** Coordinate at the top right corner. */
+ CLLocationCoordinate2D topRight;
+} MGLCoordinateQuad;
+
+
/**
Creates a new `MGLCoordinateBounds` structure from the given southwest and
northeast coordinates.
@@ -56,6 +74,33 @@ NS_INLINE MGLCoordinateBounds MGLCoordinateBoundsMake(CLLocationCoordinate2D sw,
return bounds;
}
+/**
+ Creates a new `MGLCoordinateQuad` structure from the given top left,
+ bottom left, bottom right, and top right coordinates.
+ */
+NS_INLINE MGLCoordinateQuad MGLCoordinateQuadMake(CLLocationCoordinate2D topLeft, CLLocationCoordinate2D bottomLeft, CLLocationCoordinate2D bottomRight, CLLocationCoordinate2D topRight) {
+ MGLCoordinateQuad quad;
+ quad.topLeft = topLeft;
+ quad.bottomLeft = bottomLeft;
+ quad.bottomRight = bottomRight;
+ quad.topRight = topRight;
+ return quad;
+}
+
+/**
+ Creates a new `MGLCoordinateQuad` structure from the given `MGLCoordinateBounds`.
+ The returned quad uses the bounds' northeast coordinate as the top right, and the
+ southwest coordinate at the bottom left.
+ */
+NS_INLINE MGLCoordinateQuad MGLCoordinateQuadFromCoordinateBounds(MGLCoordinateBounds bounds) {
+ MGLCoordinateQuad quad;
+ quad.topLeft = CLLocationCoordinate2DMake(bounds.ne.latitude, bounds.sw.longitude);
+ quad.bottomLeft = bounds.sw;
+ quad.bottomRight = CLLocationCoordinate2DMake(bounds.sw.latitude, bounds.ne.longitude);
+ quad.topRight = bounds.ne;
+ return quad;
+}
+
/** Returns `YES` if the two coordinate bounds are equal to each other. */
NS_INLINE BOOL MGLCoordinateBoundsEqualToCoordinateBounds(MGLCoordinateBounds bounds1, MGLCoordinateBounds bounds2) {
return (bounds1.sw.latitude == bounds2.sw.latitude &&
@@ -117,6 +162,15 @@ NS_INLINE NSString *MGLStringFromCoordinateBounds(MGLCoordinateBounds bounds) {
bounds.ne.latitude, bounds.ne.longitude];
}
+/** Returns a formatted string for the given coordinate quad. */
+NS_INLINE NSString *MGLStringFromCoordinateQuad(MGLCoordinateQuad quad) {
+ return [NSString stringWithFormat:@"{ topleft = {%.1f, %.1f}, bottomleft = {%.1f, %.1f}}, bottomright = {%.1f, %.1f}, topright = {%.1f, %.1f}",
+ quad.topLeft.latitude, quad.topLeft.longitude,
+ quad.bottomLeft.latitude, quad.bottomLeft.longitude,
+ quad.bottomRight.latitude, quad.bottomRight.longitude,
+ quad.topRight.latitude, quad.topRight.longitude];
+}
+
/** Returns radians, converted from degrees. */
NS_INLINE CGFloat MGLRadiansFromDegrees(CLLocationDegrees degrees) {
return (CGFloat)(degrees * M_PI) / 180;
diff --git a/platform/darwin/src/MGLGeometry_Private.h b/platform/darwin/src/MGLGeometry_Private.h
index 7ad8314a79..88fcf5b576 100644
--- a/platform/darwin/src/MGLGeometry_Private.h
+++ b/platform/darwin/src/MGLGeometry_Private.h
@@ -8,6 +8,7 @@
#import <mbgl/util/geo.hpp>
#import <mbgl/util/geometry.hpp>
+#import <array>
typedef double MGLLocationRadians;
typedef double MGLRadianDistance;
typedef double MGLRadianDirection;
@@ -56,6 +57,20 @@ NS_INLINE mbgl::LatLngBounds MGLLatLngBoundsFromCoordinateBounds(MGLCoordinateBo
MGLLatLngFromLocationCoordinate2D(coordinateBounds.ne));
}
+NS_INLINE std::array<mbgl::LatLng, 4> MGLLatLngArrayFromCoordinateQuad(MGLCoordinateQuad quad) {
+ return { MGLLatLngFromLocationCoordinate2D(quad.topLeft),
+ MGLLatLngFromLocationCoordinate2D(quad.topRight),
+ MGLLatLngFromLocationCoordinate2D(quad.bottomRight),
+ MGLLatLngFromLocationCoordinate2D(quad.bottomLeft) };
+}
+
+NS_INLINE MGLCoordinateQuad MGLCoordinateQuadFromLatLngArray(std::array<mbgl::LatLng, 4> quad) {
+ return { MGLLocationCoordinate2DFromLatLng(quad[0]),
+ MGLLocationCoordinate2DFromLatLng(quad[3]),
+ MGLLocationCoordinate2DFromLatLng(quad[2]),
+ MGLLocationCoordinate2DFromLatLng(quad[1]) };
+}
+
#if TARGET_OS_IPHONE
NS_INLINE mbgl::EdgeInsets MGLEdgeInsetsFromNSEdgeInsets(UIEdgeInsets insets) {
return { insets.top, insets.left, insets.bottom, insets.right };
diff --git a/platform/darwin/src/MGLImageSource.h b/platform/darwin/src/MGLImageSource.h
new file mode 100644
index 0000000000..21487d9739
--- /dev/null
+++ b/platform/darwin/src/MGLImageSource.h
@@ -0,0 +1,94 @@
+#import "MGLSource.h"
+
+#import "MGLFoundation.h"
+#import "MGLTypes.h"
+#import "MGLGeometry.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+MGL_EXPORT
+/**
+ `MGLImageSource` is a content source that is used for a georeferenced raster
+ image to be shown on the map. The georeferenced image scales and rotates as the
+ user zooms and rotates the map. Images may also be used as icons or patterns
+ in a style layer. To register an image for use as an icon or pattern,
+ use the `-[MGLStyle setImage:forName:]` method. To configure a point
+ annotation’s image, use the `MGLAnnotationImage` class.
+
+ The geographic location of the raster image content, supplied with
+ `MGLCoordinateQuad`, can be non-axis aligned.
+ `MGLImageSource` supports raster content from `NSURL`, `NSImage` (macOS), or
+ `UIImage` (iOS).
+ An image source is added to an `MGLStyle` object along with one or more
+ `MGLRasterStyleLayer` objects. Use a raster style layer to control the
+ appearance of content supplied by the image source.
+
+ Each
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-image"><code>image</code></a>
+ source defined by the style JSON file is represented at runtime by an
+ `MGLImageSource` object that you can use to initialize new style layers. You
+ can also add and remove sources dynamically using methods such as
+ `-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`.
+
+ ### Example
+
+ ```swift
+ let coordinates = MGLCoordinateQuad(
+ topLeft: CLLocationCoordinate2D(latitude: 46.437, longitude: -80.425),
+ bottomLeft: CLLocationCoordinate2D(latitude: 37.936, longitude: -80.425),
+ bottomRight: CLLocationCoordinate2D(latitude: 37.936, longitude: -71.516),
+ topRight: CLLocationCoordinate2D(latitude: 46.437, longitude: -71.516))
+ let source = MGLImageSource(identifier: "radar", coordinateQuad: coordinates, url: URL(string: "https://www.mapbox.com/mapbox-gl-js/assets/radar.gif")!)
+ mapView.style?.addSource(source)
+ ```
+ */
+MGL_EXPORT
+@interface MGLImageSource : MGLSource
+
+#pragma mark Initializing a Source
+
+/**
+ Returns a georeferenced image source with an identifier, coordinates and a URL.
+
+ @param identifier A string that uniquely identifies the source.
+ @param coordinateQuad the top left, top right, bottom right, and bottom left coordinates for the image.
+ @param url An HTTP(S) URL, absolute file URL, or local file URL relative to the
+ current application’s resource bundle.
+ @return An initialized shape source.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier coordinateQuad:(MGLCoordinateQuad)coordinateQuad URL:(NSURL *)url;
+
+/**
+ Returns a georeferenced image source with an identifier, coordinates and an image.
+
+ @param identifier A string that uniquely identifies the source.
+ @param coordinateQuad The top left, top right, bottom right, and bottom left coordinates for the image.
+ @param image The image to display for the source.
+ @return An initialized shape source.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier coordinateQuad:(MGLCoordinateQuad)coordinateQuad image:(MGLImage *)image;
+
+#pragma mark Accessing a Source’s Content
+
+/**
+ The URL to the source image.
+
+ If the receiver was initialized using `-initWithIdentifier:coordinateQuad:image:` or
+ the `image` property is set, this property is set to `nil`.
+ */
+@property (nonatomic, copy, nullable)NSURL *URL;
+
+/**
+ The source image.
+
+ If the receiver was initialized using `-initWithIdentifier:coordinateQuad:URL:` or if the `URL` property is set, this property is set to `nil`.
+ */
+@property (nonatomic, retain, nullable)MGLImage *image;
+
+/**
+ The coordinates at which the corners of the source image will be placed.
+ */
+@property (nonatomic) MGLCoordinateQuad coordinates;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLImageSource.mm b/platform/darwin/src/MGLImageSource.mm
new file mode 100644
index 0000000000..351247e901
--- /dev/null
+++ b/platform/darwin/src/MGLImageSource.mm
@@ -0,0 +1,92 @@
+#import "MGLImageSource.h"
+
+#import "MGLGeometry_Private.h"
+#import "MGLSource_Private.h"
+#import "MGLTileSource_Private.h"
+#import "NSURL+MGLAdditions.h"
+#if TARGET_OS_IPHONE
+ #import "UIImage+MGLAdditions.h"
+#else
+ #import "NSImage+MGLAdditions.h"
+#endif
+
+#include <mbgl/style/sources/image_source.hpp>
+#include <mbgl/util/premultiply.hpp>
+
+@interface MGLImageSource ()
+- (instancetype)initWithIdentifier:(NSString *)identifier coordinateQuad:(MGLCoordinateQuad)coordinateQuad NS_DESIGNATED_INITIALIZER;
+
+@property (nonatomic, readonly) mbgl::style::ImageSource *rawSource;
+
+@end
+
+@implementation MGLImageSource
+
+- (instancetype)initWithIdentifier:(NSString *)identifier coordinateQuad:(MGLCoordinateQuad)coordinateQuad {
+
+ const auto coordsArray = MGLLatLngArrayFromCoordinateQuad(coordinateQuad);
+ auto source = std::make_unique<mbgl::style::ImageSource>(identifier.UTF8String, coordsArray);
+ return self = [super initWithPendingSource:std::move(source)];
+}
+
+
+- (instancetype)initWithIdentifier:(NSString *)identifier coordinateQuad:(MGLCoordinateQuad)coordinateQuad URL:(NSURL *)url {
+ self = [self initWithIdentifier:identifier coordinateQuad: coordinateQuad];
+ self.URL = url;
+ return self;
+}
+
+
+- (instancetype)initWithIdentifier:(NSString *)identifier coordinateQuad:(MGLCoordinateQuad)coordinateQuad image:(MGLImage *)image {
+ self = [self initWithIdentifier:identifier coordinateQuad: coordinateQuad];
+ self.image = image;
+
+ return self;
+}
+
+- (NSURL *)URL {
+ auto url = self.rawSource->getURL();
+ return url ? [NSURL URLWithString:@(url->c_str())] : nil;
+}
+
+- (void)setURL:(NSURL *)url {
+ if (url) {
+ self.rawSource->setURL(url.mgl_URLByStandardizingScheme.absoluteString.UTF8String);
+ _image = nil;
+ } else {
+ self.image = nullptr;
+ }
+}
+
+- (void)setImage:(MGLImage *)image {
+ if (image != nullptr) {
+ self.rawSource->setImage(image.mgl_premultipliedImage);
+ } else {
+ self.rawSource->setImage(mbgl::PremultipliedImage({0,0}));
+ }
+ _image = image;
+}
+
+- (MGLCoordinateQuad)coordinates {
+ return MGLCoordinateQuadFromLatLngArray(self.rawSource->getCoordinates());
+}
+
+- (void)setCoordinates: (MGLCoordinateQuad)coordinateQuad {
+ self.rawSource->setCoordinates(MGLLatLngArrayFromCoordinateQuad(coordinateQuad));
+}
+
+- (NSString *)description {
+ return [NSString stringWithFormat:@"<%@: %p; identifier = %@; coordinates = %@; URL = %@; image = %@>",
+ NSStringFromClass([self class]), (void *)self, self.identifier, MGLStringFromCoordinateQuad(self.coordinates), self.URL, self.image];
+}
+
+- (mbgl::style::ImageSource *)rawSource {
+ return (mbgl::style::ImageSource *)super.rawSource;
+}
+
+- (NSString *)attributionHTMLString {
+ auto attribution = self.rawSource->getAttribution();
+ return attribution ? @(attribution->c_str()) : nil;
+}
+
+@end
diff --git a/platform/darwin/src/MGLLight.h b/platform/darwin/src/MGLLight.h
index 50db3f45fd..55b789f043 100644
--- a/platform/darwin/src/MGLLight.h
+++ b/platform/darwin/src/MGLLight.h
@@ -27,7 +27,7 @@ typedef NS_ENUM(NSUInteger, MGLLightAnchor) {
A structure containing information about the position of the light source
relative to lit geometries.
*/
-typedef struct __attribute__((objc_boxable)) MGLSphericalPosition {
+typedef struct MGLSphericalPosition {
/** Distance from the center of the base of an object to its light. */
CGFloat radial;
/** Position of the light relative to 0° (0° when `MGLLight.anchor` is set to viewport corresponds
diff --git a/platform/darwin/src/MGLLineStyleLayer.h b/platform/darwin/src/MGLLineStyleLayer.h
index 38513652c5..46025ddbf0 100644
--- a/platform/darwin/src/MGLLineStyleLayer.h
+++ b/platform/darwin/src/MGLLineStyleLayer.h
@@ -149,8 +149,18 @@ MGL_EXPORT
You can set this property to an instance of:
* `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineJoin;
@@ -543,6 +553,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineWidth;
diff --git a/platform/darwin/src/MGLLineStyleLayer.mm b/platform/darwin/src/MGLLineStyleLayer.mm
index 8b90efd0c4..5b2652cdeb 100644
--- a/platform/darwin/src/MGLLineStyleLayer.mm
+++ b/platform/darwin/src/MGLLineStyleLayer.mm
@@ -109,7 +109,7 @@ namespace mbgl {
- (void)setLineJoin:(MGLStyleValue<NSValue *> *)lineJoin {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toEnumPropertyValue(lineJoin);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toDataDrivenPropertyValue(lineJoin);
self.rawLayer->setLineJoin(mbglValue);
}
@@ -118,9 +118,9 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getLineJoin();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toEnumStyleValue(self.rawLayer->getDefaultLineJoin());
+ return MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toDataDrivenStyleValue(self.rawLayer->getDefaultLineJoin());
}
- return MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toDataDrivenStyleValue(propertyValue);
}
- (void)setLineMiterLimit:(MGLStyleValue<NSNumber *> *)lineMiterLimit {
@@ -480,7 +480,7 @@ namespace mbgl {
- (void)setLineWidth:(MGLStyleValue<NSNumber *> *)lineWidth {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(lineWidth);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(lineWidth);
self.rawLayer->setLineWidth(mbglValue);
}
@@ -489,9 +489,9 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getLineWidth();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultLineWidth());
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultLineWidth());
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setLineWidthTransition:(MGLTransition )transition {
diff --git a/platform/darwin/src/MGLMapSnapshotter.h b/platform/darwin/src/MGLMapSnapshotter.h
new file mode 100644
index 0000000000..a2a4f1b331
--- /dev/null
+++ b/platform/darwin/src/MGLMapSnapshotter.h
@@ -0,0 +1,105 @@
+#import <Foundation/Foundation.h>
+#import "MGLTypes.h"
+#import "MGLGeometry.h"
+#import "MGLMapCamera.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+MGL_EXPORT
+/**
+ The options to use when creating images with the `MGLMapsnapshotter`.
+ */
+@interface MGLMapSnapshotOptions : NSObject
+
+/**
+ Creates a set of options with the minimum required information
+ @param styleURL the style url to use
+ @param camera the camera settings
+ @param size the image size
+ */
+- (instancetype)initWithStyleURL:(NSURL*)styleURL camera:(MGLMapCamera*)camera size:(CGSize)size;
+
+#pragma mark - Configuring the map
+
+/**
+ The style URL for these options.
+ */
+@property (nonatomic, readonly) NSURL* styleURL;
+
+/**
+ The zoom. Default is 0.
+ */
+@property (nonatomic) double zoom;
+
+/**
+ The `MGLMapcamera` options to use.
+ */
+@property (nonatomic) MGLMapCamera* camera;
+
+/**
+ A region to capture. Overrides the center coordinate
+ in the mapCamera options if set
+ */
+@property (nonatomic) MGLCoordinateBounds region;
+
+#pragma mark - Configuring the image
+
+/**
+ The size of the output image. Minimum is 64x64
+ */
+@property (nonatomic, readonly) CGSize size;
+
+/**
+ The scale of the output image. Defaults to the main screen scale.
+ Minimum is 1.
+ */
+@property (nonatomic) CGFloat scale;
+
+@end
+
+/**
+ A block to processes the result or error of a snapshot request.
+
+ The result will be either an `MGLImage` or a `NSError`
+
+ @param snapshot The image that was generated or `nil` if an error occurred.
+ @param error The eror that occured or `nil` when succesful.
+ */
+typedef void (^MGLMapSnapshotCompletionHandler)(MGLImage* _Nullable snapshot, NSError* _Nullable error);
+
+/**
+ A utility object for capturing map-based images.
+ */
+MGL_EXPORT
+@interface MGLMapSnapshotter : NSObject
+
+- (instancetype)initWithOptions:(MGLMapSnapshotOptions*)options;
+
+/**
+ Starts the snapshot creation and executes the specified block with the result.
+
+ @param completionHandler The block to handle the result in.
+ */
+- (void)startWithCompletionHandler:(MGLMapSnapshotCompletionHandler)completionHandler;
+
+/**
+ Starts the snapshot creation and executes the specified block with the result on the specified queue.
+
+ @param queue The queue to handle the result on.
+ @param completionHandler The block to handle the result in.
+ */
+- (void)startWithQueue:(dispatch_queue_t)queue completionHandler:(MGLMapSnapshotCompletionHandler)completionHandler;
+
+/**
+ Cancels the snapshot creation request, if any.
+ */
+- (void)cancel;
+
+/**
+ Indicates whether as snapshot is currently being generated.
+ */
+@property (nonatomic, readonly, getter=isLoading) BOOL loading;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm
new file mode 100644
index 0000000000..c81fd39c4a
--- /dev/null
+++ b/platform/darwin/src/MGLMapSnapshotter.mm
@@ -0,0 +1,163 @@
+#import "MGLMapSnapshotter.h"
+
+#import <mbgl/actor/actor.hpp>
+#import <mbgl/actor/scheduler.hpp>
+#import <mbgl/util/geo.hpp>
+#import <mbgl/map/map_snapshotter.hpp>
+#import <mbgl/map/camera.hpp>
+#import <mbgl/storage/default_file_source.hpp>
+#import <mbgl/util/default_thread_pool.hpp>
+#import <mbgl/util/string.hpp>
+#import <mbgl/util/shared_thread_pool.hpp>
+
+#import "MGLOfflineStorage_Private.h"
+#import "MGLGeometry_Private.h"
+#import "NSBundle+MGLAdditions.h"
+
+#if TARGET_OS_IPHONE
+#import "UIImage+MGLAdditions.h"
+#else
+#import "NSImage+MGLAdditions.h"
+#endif
+
+@implementation MGLMapSnapshotOptions
+
+- (instancetype _Nonnull)initWithStyleURL:(NSURL* _Nonnull)styleURL camera:(MGLMapCamera*)camera size:(CGSize) size;
+{
+ self = [super init];
+ if (self) {
+ _styleURL = styleURL;
+ _size = size;
+ _camera = camera;
+#if TARGET_OS_IPHONE
+ _scale = [UIScreen mainScreen].scale;
+#else
+ _scale = [NSScreen mainScreen].backingScaleFactor;
+#endif
+
+ }
+ return self;
+}
+
+@end
+
+@implementation MGLMapSnapshotter {
+
+ std::shared_ptr<mbgl::ThreadPool> mbglThreadPool;
+ std::unique_ptr<mbgl::MapSnapshotter> mbglMapSnapshotter;
+ std::unique_ptr<mbgl::Actor<mbgl::MapSnapshotter::Callback>> snapshotCallback;
+}
+
+- (instancetype)initWithOptions:(MGLMapSnapshotOptions*)options;
+{
+ self = [super init];
+ if (self) {
+ _loading = false;
+
+ mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource;
+ mbglThreadPool = mbgl::sharedThreadPool();
+
+ std::string styleURL = std::string([options.styleURL.absoluteString UTF8String]);
+
+ // Size; taking into account the minimum texture size for OpenGL ES
+ mbgl::Size size = {
+ static_cast<uint32_t>(MAX(options.size.width, 64)),
+ static_cast<uint32_t>(MAX(options.size.height, 64))
+ };
+
+ float pixelRatio = MAX(options.scale, 1);
+
+ // Camera options
+ mbgl::CameraOptions cameraOptions;
+ if (CLLocationCoordinate2DIsValid(options.camera.centerCoordinate)) {
+ cameraOptions.center = MGLLatLngFromLocationCoordinate2D(options.camera.centerCoordinate);
+ }
+ cameraOptions.angle = MAX(0, options.camera.heading) * mbgl::util::DEG2RAD;
+ cameraOptions.zoom = MAX(0, options.zoom);
+ cameraOptions.pitch = MAX(0, options.camera.pitch);
+
+ // Region
+ mbgl::optional<mbgl::LatLngBounds> region;
+ if (!MGLCoordinateBoundsIsEmpty(options.region)) {
+ region = MGLLatLngBoundsFromCoordinateBounds(options.region);
+ }
+
+ // Create the snapshotter
+ mbglMapSnapshotter = std::make_unique<mbgl::MapSnapshotter>(*mbglFileSource, *mbglThreadPool, styleURL, size, pixelRatio, cameraOptions, region);
+ }
+ return self;
+}
+
+- (void)startWithCompletionHandler:(MGLMapSnapshotCompletionHandler)completion;
+{
+ [self startWithQueue:dispatch_get_main_queue() completionHandler:completion];
+}
+
+- (void)startWithQueue:(dispatch_queue_t)queue completionHandler:(MGLMapSnapshotCompletionHandler)completion;
+{
+ if ([self isLoading]) {
+ NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"Already started this snapshotter"};
+ NSError *error = [NSError errorWithDomain:MGLErrorDomain code:1 userInfo:userInfo];
+ dispatch_async(queue, ^{
+ completion(nil, error);
+ });
+ return;
+ }
+
+ _loading = true;
+
+ dispatch_async(queue, ^{
+ snapshotCallback = std::make_unique<mbgl::Actor<mbgl::MapSnapshotter::Callback>>(*mbgl::Scheduler::GetCurrent(), [=](std::exception_ptr mbglError, mbgl::PremultipliedImage image) {
+ _loading = false;
+ if (mbglError) {
+ NSString *description = @(mbgl::util::toString(mbglError).c_str());
+ NSDictionary *userInfo = @{NSLocalizedDescriptionKey: description};
+ NSError *error = [NSError errorWithDomain:MGLErrorDomain code:1 userInfo:userInfo];
+
+ // Dispatch result to origin queue
+ dispatch_async(queue, ^{
+ completion(nil, error);
+ });
+ } else {
+ MGLImage *mglImage = [[MGLImage alloc] initWithMGLPremultipliedImage:std::move(image)];
+
+ // Process image watermark in a work queue
+ dispatch_queue_t workQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+ dispatch_async(workQueue, ^{
+#if TARGET_OS_IPHONE
+ UIImage *logoImage = [UIImage imageNamed:@"mapbox" inBundle:[NSBundle mgl_frameworkBundle] compatibleWithTraitCollection:nil];
+
+ UIGraphicsBeginImageContext(mglImage.size);
+
+ [mglImage drawInRect:CGRectMake(0, 0, mglImage.size.width, mglImage.size.height)];
+ [logoImage drawInRect:CGRectMake(8, mglImage.size.height - (8 + logoImage.size.height), logoImage.size.width,logoImage.size.height)];
+ UIImage *compositedImage = UIGraphicsGetImageFromCurrentImageContext();
+
+ UIGraphicsEndImageContext();
+#else
+ NSImage *logoImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mgl_frameworkBundle] pathForResource:@"mapbox" ofType:@"pdf"]];
+ NSImage *compositedImage = mglImage;
+
+ [compositedImage lockFocus];
+ [logoImage drawInRect:CGRectMake(8, 8, logoImage.size.width,logoImage.size.height)];
+ [compositedImage unlockFocus];
+#endif
+
+ // Dispatch result to origin queue
+ dispatch_async(queue, ^{
+ completion(compositedImage, nil);
+ });
+ });
+ }
+ });
+ mbglMapSnapshotter->snapshot(snapshotCallback->self());
+ });
+}
+
+- (void)cancel;
+{
+ snapshotCallback.reset();
+ mbglMapSnapshotter.reset();
+}
+
+@end
diff --git a/platform/darwin/src/MGLMultiPoint.mm b/platform/darwin/src/MGLMultiPoint.mm
index ef46bbb0fe..240dad9614 100644
--- a/platform/darwin/src/MGLMultiPoint.mm
+++ b/platform/darwin/src/MGLMultiPoint.mm
@@ -182,7 +182,7 @@
- (mbgl::Annotation)annotationObjectWithDelegate:(__unused id <MGLMultiPointDelegate>)delegate
{
NSAssert(NO, @"Cannot add an annotation from an instance of %@", NSStringFromClass([self class]));
- return mbgl::SymbolAnnotation({mbgl::Point<double>()});
+ return mbgl::SymbolAnnotation(mbgl::Point<double>());
}
- (NSString *)description
diff --git a/platform/darwin/src/MGLOfflineStorage.h b/platform/darwin/src/MGLOfflineStorage.h
index 16f134adb1..b009f893b3 100644
--- a/platform/darwin/src/MGLOfflineStorage.h
+++ b/platform/darwin/src/MGLOfflineStorage.h
@@ -154,6 +154,8 @@ typedef NS_ENUM(NSUInteger, MGLResourceKind) {
/** JSON part of a sprite sheet. It is constructed of the prefix in
https://www.mapbox.com/mapbox-gl-js/style-spec/#root-sprite and a JSON file extension. */
MGLResourceKindSpriteJSON,
+ /** Image data for a georeferenced image source. **/
+ MGLResourceKindImage,
};
/**
diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm
index 81774ad3cb..7085aa58e5 100644
--- a/platform/darwin/src/MGLOfflineStorage.mm
+++ b/platform/darwin/src/MGLOfflineStorage.mm
@@ -10,8 +10,14 @@
#import "NSBundle+MGLAdditions.h"
#import "NSValue+MGLAdditions.h"
+#include <mbgl/actor/actor.hpp>
+#include <mbgl/actor/scheduler.hpp>
+#include <mbgl/storage/resource_transform.hpp>
+#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/string.hpp>
+#include <memory>
+
static NSString * const MGLOfflineStorageFileName = @"cache.db";
static NSString * const MGLOfflineStorageFileName3_2_0_beta_1 = @"offline.db";
@@ -36,7 +42,9 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
@end
-@implementation MGLOfflineStorage
+@implementation MGLOfflineStorage {
+ std::unique_ptr<mbgl::Actor<mbgl::ResourceTransform>> _mbglResourceTransform;
+}
+ (instancetype)sharedOfflineStorage {
static dispatch_once_t onceToken;
@@ -74,7 +82,7 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
- (void)setDelegate:(id<MGLOfflineStorageDelegate>)newValue {
_delegate = newValue;
if ([self.delegate respondsToSelector:@selector(offlineStorage:URLForResourceOfKind:withURL:)]) {
- _mbglFileSource->setResourceTransform([offlineStorage = self](auto kind_, std::string&& url_) -> std::string {
+ _mbglResourceTransform = std::make_unique<mbgl::Actor<mbgl::ResourceTransform>>(*mbgl::Scheduler::GetCurrent(), [offlineStorage = self](auto kind_, const std::string&& url_) -> std::string {
NSURL* url =
[NSURL URLWithString:[[NSString alloc] initWithBytes:url_.data()
length:url_.length()
@@ -99,6 +107,9 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
case mbgl::Resource::Kind::SpriteJSON:
kind = MGLResourceKindSpriteJSON;
break;
+ case mbgl::Resource::Kind::Image:
+ kind = MGLResourceKindImage;
+ break;
case mbgl::Resource::Kind::Unknown:
kind = MGLResourceKindUnknown;
break;
@@ -109,8 +120,11 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
withURL:url];
return url.absoluteString.UTF8String;
});
+
+ _mbglFileSource->setResourceTransform(_mbglResourceTransform->self());
} else {
- _mbglFileSource->setResourceTransform(nullptr);
+ _mbglResourceTransform.reset();
+ _mbglFileSource->setResourceTransform({});
}
}
diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.h b/platform/darwin/src/MGLOpenGLStyleLayer.h
index bdad5f9d07..0b494e8062 100644
--- a/platform/darwin/src/MGLOpenGLStyleLayer.h
+++ b/platform/darwin/src/MGLOpenGLStyleLayer.h
@@ -8,6 +8,7 @@
NS_ASSUME_NONNULL_BEGIN
@class MGLMapView;
+@class MGLStyle;
typedef struct MGLStyleLayerDrawingContext {
CGSize size;
@@ -21,7 +22,7 @@ typedef struct MGLStyleLayerDrawingContext {
MGL_EXPORT
@interface MGLOpenGLStyleLayer : MGLStyleLayer
-@property (nonatomic, weak, readonly) MGLMapView *mapView;
+@property (nonatomic, weak, readonly) MGLStyle *style;
- (instancetype)initWithIdentifier:(NSString *)identifier;
diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.mm b/platform/darwin/src/MGLOpenGLStyleLayer.mm
index 39eda758eb..36a3c20c97 100644
--- a/platform/darwin/src/MGLOpenGLStyleLayer.mm
+++ b/platform/darwin/src/MGLOpenGLStyleLayer.mm
@@ -4,7 +4,6 @@
#import "MGLStyle_Private.h"
#import "MGLStyleLayer_Private.h"
-#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/math/wrap.hpp>
@@ -17,7 +16,7 @@
*/
void MGLPrepareCustomStyleLayer(void *context) {
MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context;
- [layer didMoveToMapView:layer.mapView];
+ [layer didMoveToMapView:layer.style.mapView];
}
/**
@@ -37,7 +36,7 @@ void MGLDrawCustomStyleLayer(void *context, const mbgl::style::CustomLayerRender
.pitch = static_cast<CGFloat>(params.pitch),
.fieldOfView = static_cast<CGFloat>(params.fieldOfView),
};
- [layer drawInMapView:layer.mapView withContext:drawingContext];
+ [layer drawInMapView:layer.style.mapView withContext:drawingContext];
}
/**
@@ -49,7 +48,7 @@ void MGLDrawCustomStyleLayer(void *context, const mbgl::style::CustomLayerRender
*/
void MGLFinishCustomStyleLayer(void *context) {
MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context;
- [layer willMoveFromMapView:layer.mapView];
+ [layer willMoveFromMapView:layer.style.mapView];
}
/**
@@ -75,12 +74,12 @@ void MGLFinishCustomStyleLayer(void *context) {
@property (nonatomic, readonly) mbgl::style::CustomLayer *rawLayer;
/**
- The map view whose style currently contains the layer.
+ The style currently containing the layer.
- If the layer is not currently part of any map view’s style, this property is
+ If the layer is not currently part of any style, this property is
set to `nil`.
*/
-@property (nonatomic, weak, readwrite) MGLMapView *mapView;
+@property (nonatomic, weak, readwrite) MGLStyle *style;
@end
@@ -112,24 +111,24 @@ void MGLFinishCustomStyleLayer(void *context) {
#pragma mark - Adding to and removing from a map view
-- (void)setMapView:(MGLMapView *)mapView {
- if (_mapView && mapView) {
+- (void)setStyle:(MGLStyle *)style {
+ if (_style && style) {
[NSException raise:@"MGLLayerReuseException"
format:@"%@ cannot be added to more than one MGLStyle at a time.", self];
}
- _mapView.style.openGLLayers[self.identifier] = nil;
- _mapView = mapView;
- _mapView.style.openGLLayers[self.identifier] = self;
+ _style.openGLLayers[self.identifier] = nil;
+ _style = style;
+ _style.openGLLayers[self.identifier] = self;
}
-- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer {
- self.mapView = mapView;
- [super addToMapView:mapView belowLayer:otherLayer];
+- (void)addToStyle:(MGLStyle *)style belowLayer:(MGLStyleLayer *)otherLayer {
+ self.style = style;
+ [super addToStyle:style belowLayer:otherLayer];
}
-- (void)removeFromMapView:(MGLMapView *)mapView {
- [super removeFromMapView:mapView];
- self.mapView = nil;
+- (void)removeFromStyle:(MGLStyle *)style {
+ [super removeFromStyle:style];
+ self.style = nil;
}
/**
@@ -193,7 +192,7 @@ void MGLFinishCustomStyleLayer(void *context) {
causing the `-drawInMapView:withContext:` method to be called.
*/
- (void)setNeedsDisplay {
- [self.mapView setNeedsGLDisplay];
+ [self.style.mapView setNeedsGLDisplay];
}
@end
diff --git a/platform/darwin/src/MGLRendererFrontend.h b/platform/darwin/src/MGLRendererFrontend.h
new file mode 100644
index 0000000000..76904d008b
--- /dev/null
+++ b/platform/darwin/src/MGLRendererFrontend.h
@@ -0,0 +1,70 @@
+#include <mbgl/renderer/backend_scope.hpp>
+#include <mbgl/renderer/renderer.hpp>
+#include <mbgl/renderer/renderer_backend.hpp>
+#include <mbgl/renderer/renderer_frontend.hpp>
+#include <mbgl/util/async_task.hpp>
+#include <mbgl/util/optional.hpp>
+
+
+/**
+ The RenderFrontend is passed to the Map to facilitate rendering in a platform
+ dependent way.
+ */
+class MGLRenderFrontend : public mbgl::RendererFrontend
+{
+public:
+ MGLRenderFrontend(std::unique_ptr<mbgl::Renderer> renderer_, MGLMapView* nativeView_, mbgl::RendererBackend& mbglBackend_, bool async = false)
+ : renderer(std::move(renderer_))
+ , nativeView(nativeView_)
+ , mbglBackend(mbglBackend_) {
+ if (async) {
+ asyncInvalidate.emplace([&]() {
+ [nativeView setNeedsGLDisplay];
+ });
+ }
+ }
+
+ void reset() override {
+ if (renderer) {
+ renderer.reset();
+ }
+ }
+
+ void update(std::shared_ptr<mbgl::UpdateParameters> updateParameters_) override {
+ updateParameters = std::move(updateParameters_);
+ if (asyncInvalidate) {
+ asyncInvalidate->send();
+ } else {
+ [nativeView setNeedsGLDisplay];
+ }
+ }
+
+ void setObserver(mbgl::RendererObserver& observer) override {
+ if (!renderer) return;
+ renderer->setObserver(&observer);
+ }
+
+ void render() {
+ if (!renderer || !updateParameters) return;
+
+ mbgl::BackendScope guard { mbglBackend, mbgl::BackendScope::ScopeType::Implicit };
+
+ renderer->render(*updateParameters);
+ }
+
+ mbgl::Renderer* getRenderer() {
+ return renderer.get();
+ }
+
+ void onLowMemory() {
+ if (!renderer) return;
+ renderer->onLowMemory();
+ }
+
+private:
+ std::unique_ptr<mbgl::Renderer> renderer;
+ __weak MGLMapView *nativeView = nullptr;
+ mbgl::RendererBackend& mbglBackend;
+ std::shared_ptr<mbgl::UpdateParameters> updateParameters;
+ mbgl::optional<mbgl::util::AsyncTask> asyncInvalidate;
+};
diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm
index 023a81bba8..571cbdcc62 100644
--- a/platform/darwin/src/MGLShapeSource.mm
+++ b/platform/darwin/src/MGLShapeSource.mm
@@ -1,5 +1,6 @@
#import "MGLShapeSource_Private.h"
+#import "MGLStyle_Private.h"
#import "MGLMapView_Private.h"
#import "MGLSource_Private.h"
#import "MGLFeature_Private.h"
@@ -10,6 +11,7 @@
#include <mbgl/map/map.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
+#include <mbgl/renderer/renderer.hpp>
const MGLShapeSourceOption MGLShapeSourceOptionClustered = @"MGLShapeSourceOptionClustered";
const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius = @"MGLShapeSourceOptionClusterRadius";
@@ -97,7 +99,7 @@ const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLSh
std::vector<mbgl::Feature> features;
if (self.mapView) {
- features = self.mapView.mbglMap->querySourceFeatures(self.rawSource->getID(), { {}, optionalFilter });
+ features = self.mapView.renderer->querySourceFeatures(self.rawSource->getID(), { {}, optionalFilter });
}
return MGLFeaturesFromMBGLFeatures(features);
}
diff --git a/platform/darwin/src/MGLSource.h b/platform/darwin/src/MGLSource.h
index a504a01791..8d8c936833 100644
--- a/platform/darwin/src/MGLSource.h
+++ b/platform/darwin/src/MGLSource.h
@@ -16,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN
add and remove sources dynamically using methods such as
`-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`.
- Create instances of `MGLShapeSource` and the concrete subclasses of
+ Create instances of `MGLShapeSource`, `MGLImageSource` and the concrete subclasses of
`MGLTileSource` (`MGLVectorSource` and `MGLRasterSource`) in order to use
`MGLSource`'s properties and methods. Do not create instances of `MGLSource`
directly, and do not create your own subclasses of this class.
diff --git a/platform/darwin/src/MGLSource.mm b/platform/darwin/src/MGLSource.mm
index 7bab90e9de..6d57e14e8c 100644
--- a/platform/darwin/src/MGLSource.mm
+++ b/platform/darwin/src/MGLSource.mm
@@ -1,6 +1,8 @@
#import "MGLSource_Private.h"
+#import "MGLStyle_Private.h"
#import "MGLMapView_Private.h"
+#include <mbgl/style/style.hpp>
#include <mbgl/map/map.hpp>
#include <mbgl/style/source.hpp>
@@ -48,16 +50,16 @@
if (_pendingSource == nullptr) {
[NSException raise:@"MGLRedundantSourceException"
format:@"This instance %@ was already added to %@. Adding the same source instance " \
- "to the style more than once is invalid.", self, mapView.style];
+ "to the style more than once is invalid.", self, mapView.style];
}
-
+
_mapView = mapView;
- mapView.mbglMap->addSource(std::move(_pendingSource));
+ _mapView.style.rawStyle->addSource(std::move(_pendingSource));
}
- (void)removeFromMapView:(MGLMapView *)mapView {
- if (self.rawSource == mapView.mbglMap->getSource(self.identifier.UTF8String)) {
- _pendingSource = mapView.mbglMap->removeSource(self.identifier.UTF8String);
+ if (self.rawSource == mapView.style.rawStyle->getSource(self.identifier.UTF8String)) {
+ _pendingSource = mapView.style.rawStyle->removeSource(self.identifier.UTF8String);
_mapView = nil;
}
}
diff --git a/platform/darwin/src/MGLSource_Private.h b/platform/darwin/src/MGLSource_Private.h
index 13a3dd5a30..d7d1f66641 100644
--- a/platform/darwin/src/MGLSource_Private.h
+++ b/platform/darwin/src/MGLSource_Private.h
@@ -45,7 +45,6 @@ struct SourceWrapper {
/**
The map view whose style currently contains the source.
-
If the source is not currently part of any map view’s style, this property is
set to `nil`.
*/
@@ -53,7 +52,6 @@ struct SourceWrapper {
/**
Adds the mbgl source that this object represents to the mbgl map.
-
Once a mbgl source is added, ownership of the object is transferred to the
`mbgl::Map` and this object no longer has an active unique_ptr reference to the
`mbgl::Source`. If this object's mbgl source is in that state, the mbgl source
@@ -65,7 +63,6 @@ struct SourceWrapper {
/**
Removes the mbgl source that this object represents from the mbgl map.
-
When a mbgl source is removed, ownership of the object is transferred back
to the `MGLSource` instance and the unique_ptr reference is valid again. It is
safe to add the source back to the style after it is removed.
diff --git a/platform/darwin/src/MGLStyle.h b/platform/darwin/src/MGLStyle.h
index 4bf1f6a4dc..0b360de8fc 100644
--- a/platform/darwin/src/MGLStyle.h
+++ b/platform/darwin/src/MGLStyle.h
@@ -32,51 +32,14 @@ NS_ASSUME_NONNULL_BEGIN
static MGL_EXPORT const NSInteger MGLStyleDefaultVersion = 10;
/**
- An `MGLStyle` object represents the active map style of an `MGLMapView`. A
- style defines both the map’s content and every aspect of its appearance. Styles
- can be designed in
- <a href="https://www.mapbox.com/studio/">Mapbox Studio</a> and hosted on
- mapbox.com. `MGLStyle` provides methods for inspecting and manipulating a style
- dynamically, with classes and properties that parallel the style JSON format
- defined by the
- <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/">Mapbox Style Specification</a>.
-
- You set a map view’s active style using the `MGLMapView.styleURL` property.
- `MGLStyle` provides a set of convenience methods that return the URLs of
- <a href="https://www.mapbox.com/maps/">popular Mapbox-designed styles</a>.
- Once the `-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
- `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` method is called, signaling
- that the style has finished loading, you can use the `MGLMapView.style`
- property to obtain the map view’s `MGLStyle`.
-
- A style primarily consists of the following components:
-
- * _Content sources_ supply content to be shown on the map. Use methods such as
- `-sourceWithIdentifier:` and `-addSource:` to configure the style’s content
- sources, which are represented by `MGLSource` objects.
- * _Style layers_ manage the layout and appearance of content at specific
- z-indices in the style. Most kinds of style layers display content provided
- by a content source. Use methods such as `-layerWithIdentifier:` and
- `-addLayer:` to configure the style’s layers, which are represented by
- `MGLStyleLayer` objects.
- * _Style images_ are used as icons and patterns in style layers. Use the
- `-setImage:forName:` method to register an image as a style image.
- (Annotations are represented by annotation images rather than style images.
- To configure an annotation’s appearance, use the
- `-[MGLMapViewDelegate mapView:imageForAnnotation:]` method.)
- * The style’s _light_ is the light source affecting any 3D extruded fills.
- Use the `light` property to configure the style’s light, which is represented
- by an `MGLLight` object.
-
- The `MGLStyle`, `MGLSource`, `MGLStyleLayer`, and `MGLLight` classes are
- collectively known as the _runtime styling API_. The active style influences a
- related API, visible feature querying, which is available through methods such
- as `-[MGLMapView visibleFeaturesInRect:]`.
-
- Some terminology differs between the Mapbox Style Specification and the various
- classes associated with `MGLStyle`. Consult the
- “[Information for Style Authors](../for-style-authors.html)” guide for an
- overview of these differences.
+ The proxy object for the current map style.
+
+ MGLStyle provides a set of convenience methods for changing Mapbox
+ default styles using `-[MGLMapView styleURL]`.
+ <a href="https://www.mapbox.com/maps/">Learn more about Mapbox default styles</a>.
+
+ It is also possible to directly manipulate the current map style
+ via `-[MGLMapView style]` by updating the style's data sources or layers.
@note Wait until the map style has finished loading before modifying a map's
style via any of the `MGLStyle` instance methods below. You can use the
@@ -493,40 +456,24 @@ MGL_EXPORT
#pragma mark Managing Style Classes
/**
- Currently active style classes, represented as an array of string identifiers.
+ Support for style classes has been removed. This property always returns an empty array.
*/
-@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses __attribute__((deprecated("This property will be removed in a future release.")));
+@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses __attribute__((deprecated("This property is non-functional.")));
/**
- Returns a Boolean value indicating whether the style class with the given
- identifier is currently active.
-
- @param styleClass The style class to query for.
- @return Whether the style class is currently active.
+ Support for style classes has been removed. This method always returns NO.
*/
-- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((deprecated("This method will be removed in a future release.")));
+- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
/**
- Activates the style class with the given identifier.
-
- @param styleClass The style class to activate.
+ Support for style classes has been removed. This method is a no-op.
*/
-- (void)addStyleClass:(NSString *)styleClass __attribute__((deprecated("This method will be removed in a future release.")));
+- (void)addStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
/**
- Deactivates the style class with the given identifier.
-
- @note Style class names are not guaranteed to exist across styles or different
- versions of the same style. Applications that use this API must first set the
- style URL to an explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
- inspectable in Interface Builder, or a manually constructed `NSURL`. This
- approach also avoids style class name changes that will occur in the default
- style over time.
-
- @param styleClass The style class to deactivate.
+ Support for style classes has been removed. This method is a no-op.
*/
-- (void)removeStyleClass:(NSString *)styleClass __attribute__((deprecated("This method will be removed in a future release.")));
+- (void)removeStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
#pragma mark Managing a Style’s Images
diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm
index 23e75f211c..52efc7a85a 100644
--- a/platform/darwin/src/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
@@ -2,6 +2,7 @@
#import "MGLMapView_Private.h"
#import "MGLStyleLayer.h"
+#import "MGLStyleLayer_Private.h"
#import "MGLFillStyleLayer.h"
#import "MGLFillExtrusionStyleLayer.h"
#import "MGLLineStyleLayer.h"
@@ -11,24 +12,21 @@
#import "MGLBackgroundStyleLayer.h"
#import "MGLOpenGLStyleLayer.h"
-#import "MGLStyle_Private.h"
-#import "MGLStyleLayer_Private.h"
+#import "MGLSource.h"
#import "MGLSource_Private.h"
#import "MGLLight_Private.h"
-
-#import "NSDate+MGLAdditions.h"
-
-#import "MGLSource.h"
#import "MGLTileSource_Private.h"
#import "MGLVectorSource.h"
#import "MGLVectorSource+MGLAdditions.h"
#import "MGLRasterSource.h"
#import "MGLShapeSource.h"
+#import "MGLImageSource.h"
#import "MGLAttributionInfo_Private.h"
#include <mbgl/map/map.hpp>
#include <mbgl/util/default_styles.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/image.hpp>
#include <mbgl/style/light.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
@@ -42,6 +40,9 @@
#include <mbgl/style/sources/geojson_source.hpp>
#include <mbgl/style/sources/vector_source.hpp>
#include <mbgl/style/sources/raster_source.hpp>
+#include <mbgl/style/sources/image_source.hpp>
+
+#import "NSDate+MGLAdditions.h"
#if TARGET_OS_IPHONE
#import "UIImage+MGLAdditions.h"
@@ -73,7 +74,8 @@
@interface MGLStyle()
-@property (nonatomic, readwrite, weak) MGLMapView *mapView;
+@property (nonatomic, readonly, weak) MGLMapView *mapView;
+@property (nonatomic, readonly) mbgl::style::Style *rawStyle;
@property (readonly, copy, nullable) NSURL *URL;
@property (nonatomic, readwrite, strong) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLOpenGLStyleLayer *) *openGLLayers;
@property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, NS_DICTIONARY_OF(NSObject *, MGLTextLanguage *) *) *localizedLayersByIdentifier;
@@ -163,9 +165,10 @@ static NSURL *MGLStyleURL_trafficNight;
#pragma mark -
-- (instancetype)initWithMapView:(MGLMapView *)mapView {
+- (instancetype)initWithRawStyle:(mbgl::style::Style *)rawStyle mapView:(MGLMapView *)mapView {
if (self = [super init]) {
_mapView = mapView;
+ _rawStyle = rawStyle;
_openGLLayers = [NSMutableDictionary dictionary];
_localizedLayersByIdentifier = [NSMutableDictionary dictionary];
}
@@ -173,18 +176,18 @@ static NSURL *MGLStyleURL_trafficNight;
}
- (NSURL *)URL {
- return [NSURL URLWithString:@(self.mapView.mbglMap->getStyleURL().c_str())];
+ return [NSURL URLWithString:@(self.rawStyle->getURL().c_str())];
}
- (NSString *)name {
- std::string name = self.mapView.mbglMap->getStyleName();
+ std::string name = self.rawStyle->getName();
return name.empty() ? nil : @(name.c_str());
}
#pragma mark Sources
- (NS_SET_OF(__kindof MGLSource *) *)sources {
- auto rawSources = self.mapView.mbglMap->getSources();
+ auto rawSources = self.rawStyle->getSources();
NS_MUTABLE_SET_OF(__kindof MGLSource *) *sources = [NSMutableSet setWithCapacity:rawSources.size()];
for (auto rawSource = rawSources.begin(); rawSource != rawSources.end(); ++rawSource) {
MGLSource *source = [self sourceFromMBGLSource:*rawSource];
@@ -203,8 +206,7 @@ static NSURL *MGLStyleURL_trafficNight;
}
- (NSUInteger)countOfSources {
- auto rawSources = self.mapView.mbglMap->getSources();
- return rawSources.size();
+ return self.rawStyle->getSources().size();
}
- (MGLSource *)memberOfSources:(MGLSource *)object {
@@ -213,7 +215,7 @@ static NSURL *MGLStyleURL_trafficNight;
- (MGLSource *)sourceWithIdentifier:(NSString *)identifier
{
- auto rawSource = self.mapView.mbglMap->getSource(identifier.UTF8String);
+ auto rawSource = self.rawStyle->getSource(identifier.UTF8String);
return rawSource ? [self sourceFromMBGLSource:rawSource] : nil;
}
@@ -231,6 +233,8 @@ static NSURL *MGLStyleURL_trafficNight;
return [[MGLShapeSource alloc] initWithRawSource:geoJSONSource mapView:self.mapView];
} else if (auto rasterSource = rawSource->as<mbgl::style::RasterSource>()) {
return [[MGLRasterSource alloc] initWithRawSource:rasterSource mapView:self.mapView];
+ } else if (auto imageSource = rawSource->as<mbgl::style::ImageSource>()) {
+ return [[MGLImageSource alloc] initWithRawSource:imageSource mapView:self.mapView];
} else {
return [[MGLSource alloc] initWithRawSource:rawSource mapView:self.mapView];
}
@@ -267,7 +271,7 @@ static NSURL *MGLStyleURL_trafficNight;
// It’d be incredibly convenient to use -sources here, but this operation
// depends on the sources being sorted in ascending order by creation, as
// with the std::vector used in mbgl.
- auto rawSources = self.mapView.mbglMap->getSources();
+ auto rawSources = self.rawStyle->getSources();
NSMutableArray *infos = [NSMutableArray arrayWithCapacity:rawSources.size()];
for (auto rawSource = rawSources.begin(); rawSource != rawSources.end(); ++rawSource) {
MGLTileSource *source = (MGLTileSource *)[self sourceFromMBGLSource:*rawSource];
@@ -285,7 +289,7 @@ static NSURL *MGLStyleURL_trafficNight;
- (NS_ARRAY_OF(__kindof MGLStyleLayer *) *)layers
{
- auto layers = self.mapView.mbglMap->getLayers();
+ auto layers = self.rawStyle->getLayers();
NS_MUTABLE_ARRAY_OF(__kindof MGLStyleLayer *) *styleLayers = [NSMutableArray arrayWithCapacity:layers.size()];
for (auto layer : layers) {
MGLStyleLayer *styleLayer = [self layerFromMBGLLayer:layer];
@@ -305,12 +309,12 @@ static NSURL *MGLStyleURL_trafficNight;
- (NSUInteger)countOfLayers
{
- return self.mapView.mbglMap->getLayers().size();
+ return self.rawStyle->getLayers().size();
}
- (MGLStyleLayer *)objectInLayersAtIndex:(NSUInteger)index
{
- auto layers = self.mapView.mbglMap->getLayers();
+ auto layers = self.rawStyle->getLayers();
if (index >= layers.size()) {
[NSException raise:NSRangeException
format:@"No style layer at index %lu.", (unsigned long)index];
@@ -322,7 +326,7 @@ static NSURL *MGLStyleURL_trafficNight;
- (void)getLayers:(MGLStyleLayer **)buffer range:(NSRange)inRange
{
- auto layers = self.mapView.mbglMap->getLayers();
+ auto layers = self.rawStyle->getLayers();
if (NSMaxRange(inRange) > layers.size()) {
[NSException raise:NSRangeException
format:@"Style layer range %@ is out of bounds.", NSStringFromRange(inRange)];
@@ -342,21 +346,21 @@ static NSURL *MGLStyleURL_trafficNight;
@"Make sure the style layer was created as a member of a concrete subclass of MGLStyleLayer.",
styleLayer];
}
- auto layers = self.mapView.mbglMap->getLayers();
+ auto layers = self.rawStyle->getLayers();
if (index > layers.size()) {
[NSException raise:NSRangeException
format:@"Cannot insert style layer at out-of-bounds index %lu.", (unsigned long)index];
} else if (index == 0) {
try {
MGLStyleLayer *sibling = layers.size() ? [self layerFromMBGLLayer:layers.at(0)] : nil;
- [styleLayer addToMapView:self.mapView belowLayer:sibling];
+ [styleLayer addToStyle:self belowLayer:sibling];
} catch (const std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
} else {
try {
MGLStyleLayer *sibling = [self layerFromMBGLLayer:layers.at(index)];
- [styleLayer addToMapView:self.mapView belowLayer:sibling];
+ [styleLayer addToStyle:self belowLayer:sibling];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
@@ -365,14 +369,14 @@ static NSURL *MGLStyleURL_trafficNight;
- (void)removeObjectFromLayersAtIndex:(NSUInteger)index
{
- auto layers = self.mapView.mbglMap->getLayers();
+ auto layers = self.rawStyle->getLayers();
if (index >= layers.size()) {
[NSException raise:NSRangeException
format:@"Cannot remove style layer at out-of-bounds index %lu.", (unsigned long)index];
}
auto layer = layers.at(index);
MGLStyleLayer *styleLayer = [self layerFromMBGLLayer:layer];
- [styleLayer removeFromMapView:self.mapView];
+ [styleLayer removeFromStyle:self];
}
- (MGLStyleLayer *)layerFromMBGLLayer:(mbgl::style::Layer *)rawLayer
@@ -407,7 +411,7 @@ static NSURL *MGLStyleURL_trafficNight;
- (MGLStyleLayer *)layerWithIdentifier:(NSString *)identifier
{
- auto mbglLayer = self.mapView.mbglMap->getLayer(identifier.UTF8String);
+ auto mbglLayer = self.rawStyle->getLayer(identifier.UTF8String);
return mbglLayer ? [self layerFromMBGLLayer:mbglLayer] : nil;
}
@@ -420,7 +424,7 @@ static NSURL *MGLStyleURL_trafficNight;
layer];
}
[self willChangeValueForKey:@"layers"];
- [layer removeFromMapView:self.mapView];
+ [layer removeFromStyle:self];
[self didChangeValueForKey:@"layers"];
}
@@ -434,7 +438,7 @@ static NSURL *MGLStyleURL_trafficNight;
}
[self willChangeValueForKey:@"layers"];
try {
- [layer addToMapView:self.mapView belowLayer:nil];
+ [layer addToStyle:self belowLayer:nil];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
@@ -463,7 +467,7 @@ static NSURL *MGLStyleURL_trafficNight;
}
[self willChangeValueForKey:@"layers"];
try {
- [layer addToMapView:self.mapView belowLayer:sibling];
+ [layer addToStyle:self belowLayer:sibling];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
@@ -486,7 +490,7 @@ static NSURL *MGLStyleURL_trafficNight;
sibling];
}
- auto layers = self.mapView.mbglMap->getLayers();
+ auto layers = self.rawStyle->getLayers();
std::string siblingIdentifier = sibling.identifier.UTF8String;
NSUInteger index = 0;
for (auto layer : layers) {
@@ -505,14 +509,14 @@ static NSURL *MGLStyleURL_trafficNight;
sibling];
} else if (index + 1 == layers.size()) {
try {
- [layer addToMapView:self.mapView belowLayer:nil];
+ [layer addToStyle:self belowLayer:nil];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
} else {
MGLStyleLayer *sibling = [self layerFromMBGLLayer:layers.at(index + 1)];
try {
- [layer addToMapView:self.mapView belowLayer:sibling];
+ [layer addToStyle:self belowLayer:sibling];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
@@ -524,60 +528,32 @@ static NSURL *MGLStyleURL_trafficNight;
- (NS_ARRAY_OF(NSString *) *)styleClasses
{
- const std::vector<std::string> &appliedClasses = self.mapView.mbglMap->getClasses();
-
- NSMutableArray *returnArray = [NSMutableArray arrayWithCapacity:appliedClasses.size()];
-
- for (auto appliedClass : appliedClasses) {
- [returnArray addObject:@(appliedClass.c_str())];
- }
-
- return returnArray;
+ return @[];
}
- (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses
{
- [self setStyleClasses:appliedClasses transitionDuration:0];
}
- (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration
{
- std::vector<std::string> newAppliedClasses;
-
- for (NSString *appliedClass in appliedClasses)
- {
- newAppliedClasses.push_back([appliedClass UTF8String]);
- }
-
- mbgl::style::TransitionOptions transition { { MGLDurationFromTimeInterval(transitionDuration) } };
- self.mapView.mbglMap->setTransitionOptions(transition);
- self.mapView.mbglMap->setClasses(newAppliedClasses);
}
- (NSUInteger)countOfStyleClasses {
- const auto &classes = self.mapView.mbglMap->getClasses();
- return classes.size();
+ return 0;
}
- (BOOL)hasStyleClass:(NSString *)styleClass
{
- return styleClass && self.mapView.mbglMap->hasClass([styleClass UTF8String]);
+ return NO;
}
- (void)addStyleClass:(NSString *)styleClass
{
- if (styleClass)
- {
- self.mapView.mbglMap->addClass([styleClass UTF8String]);
- }
}
- (void)removeStyleClass:(NSString *)styleClass
{
- if (styleClass)
- {
- self.mapView.mbglMap->removeClass([styleClass UTF8String]);
- }
}
#pragma mark Style images
@@ -593,7 +569,7 @@ static NSURL *MGLStyleURL_trafficNight;
format:@"Cannot assign image %@ to a nil name.", image];
}
- self.mapView.mbglMap->addImage([name UTF8String], image.mgl_styleImage);
+ self.rawStyle->addImage([image mgl_styleImageWithIdentifier:name]);
}
- (void)removeImageForName:(NSString *)name
@@ -603,7 +579,7 @@ static NSURL *MGLStyleURL_trafficNight;
format:@"Cannot remove image with nil name."];
}
- self.mapView.mbglMap->removeImage([name UTF8String]);
+ self.rawStyle->removeImage([name UTF8String]);
}
- (MGLImage *)imageForName:(NSString *)name
@@ -613,7 +589,7 @@ static NSURL *MGLStyleURL_trafficNight;
format:@"Cannot get image with nil name."];
}
- auto styleImage = self.mapView.mbglMap->getImage([name UTF8String]);
+ auto styleImage = self.rawStyle->getImage([name UTF8String]);
return styleImage ? [[MGLImage alloc] initWithMGLStyleImage:styleImage] : nil;
}
@@ -621,17 +597,17 @@ static NSURL *MGLStyleURL_trafficNight;
- (void)setTransition:(MGLTransition)transition
{
- auto transitionOptions = self.mapView.mbglMap->getTransitionOptions();
+ auto transitionOptions = self.rawStyle->getTransitionOptions();
transitionOptions.duration = MGLDurationFromTimeInterval(transition.duration);
transitionOptions.delay = MGLDurationFromTimeInterval(transition.delay);
- self.mapView.mbglMap->setTransitionOptions(transitionOptions);
+ self.rawStyle->setTransitionOptions(transitionOptions);
}
- (MGLTransition)transition
{
MGLTransition transition;
- const mbgl::style::TransitionOptions transitionOptions = self.mapView.mbglMap->getTransitionOptions();
+ const mbgl::style::TransitionOptions transitionOptions = self.rawStyle->getTransitionOptions();
transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
@@ -644,12 +620,12 @@ static NSURL *MGLStyleURL_trafficNight;
- (void)setLight:(MGLLight *)light
{
std::unique_ptr<mbgl::style::Light> mbglLight = std::make_unique<mbgl::style::Light>([light mbglLight]);
- self.mapView.mbglMap->setLight(std::move(mbglLight));
+ self.rawStyle->setLight(std::move(mbglLight));
}
- (MGLLight *)light
{
- auto mbglLight = self.mapView.mbglMap->getLight();
+ auto mbglLight = self.rawStyle->getLight();
MGLLight *light = [[MGLLight alloc] initWithMBGLLight:mbglLight];
return light;
}
diff --git a/platform/darwin/src/MGLStyleLayer.mm b/platform/darwin/src/MGLStyleLayer.mm
index 4bfaea934b..6400b8fcbf 100644
--- a/platform/darwin/src/MGLStyleLayer.mm
+++ b/platform/darwin/src/MGLStyleLayer.mm
@@ -1,7 +1,7 @@
#import "MGLStyleLayer_Private.h"
-#import "MGLMapView_Private.h"
+#import "MGLStyle_Private.h"
-#include <mbgl/map/map.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/layer.hpp>
@interface MGLStyleLayer ()
@@ -30,26 +30,26 @@
return self;
}
-- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
+- (void)addToStyle:(MGLStyle *)style belowLayer:(MGLStyleLayer *)otherLayer
{
if (_pendingLayer == nullptr) {
[NSException raise:@"MGLRedundantLayerException"
format:@"This instance %@ was already added to %@. Adding the same layer instance " \
- "to the style more than once is invalid.", self, mapView.style];
+ "to the style more than once is invalid.", self, style];
}
if (otherLayer) {
const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
- mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
+ style.rawStyle->addLayer(std::move(_pendingLayer), belowLayerId);
} else {
- mapView.mbglMap->addLayer(std::move(_pendingLayer));
+ style.rawStyle->addLayer(std::move(_pendingLayer));
}
}
-- (void)removeFromMapView:(MGLMapView *)mapView
+- (void)removeFromStyle:(MGLStyle *)style
{
- if (self.rawLayer == mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
- _pendingLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
+ if (self.rawLayer == style.rawStyle->getLayer(self.identifier.UTF8String)) {
+ _pendingLayer = style.rawStyle->removeLayer(self.identifier.UTF8String);
}
}
diff --git a/platform/darwin/src/MGLStyleLayer_Private.h b/platform/darwin/src/MGLStyleLayer_Private.h
index ed8ec31755..9bee013c3d 100644
--- a/platform/darwin/src/MGLStyleLayer_Private.h
+++ b/platform/darwin/src/MGLStyleLayer_Private.h
@@ -34,7 +34,7 @@ struct LayerWrapper {
} \
} while (NO);
-@class MGLMapView;
+@class MGLStyle;
@interface MGLStyleLayer (Private)
@@ -69,7 +69,7 @@ struct LayerWrapper {
`mbgl::Map` and this object no longer has an active unique_ptr reference to the
`mbgl::style::Layer`.
*/
-- (void)addToMapView:(MGLMapView *)mapView belowLayer:(nullable MGLStyleLayer *)otherLayer;
+- (void)addToStyle:(MGLStyle *)style belowLayer:(nullable MGLStyleLayer *)otherLayer;
/**
Removes the mbgl style layer that this object represents from the mbgl map.
@@ -78,7 +78,7 @@ struct LayerWrapper {
to the `MGLStyleLayer` instance and the unique_ptr reference is valid again. It
is safe to add the layer back to the style after it is removed.
*/
-- (void)removeFromMapView:(MGLMapView *)mapView;
+- (void)removeFromStyle:(MGLStyle *)style;
@end
diff --git a/platform/darwin/src/MGLStyle_Private.h b/platform/darwin/src/MGLStyle_Private.h
index 23ce8fbee0..92b08e844b 100644
--- a/platform/darwin/src/MGLStyle_Private.h
+++ b/platform/darwin/src/MGLStyle_Private.h
@@ -5,15 +5,22 @@
NS_ASSUME_NONNULL_BEGIN
+namespace mbgl {
+ namespace style {
+ class Style;
+ }
+}
+
@class MGLAttributionInfo;
@class MGLMapView;
@class MGLOpenGLStyleLayer;
@interface MGLStyle (Private)
-- (instancetype)initWithMapView:(MGLMapView *)mapView;
+- (instancetype)initWithRawStyle:(mbgl::style::Style *)rawStyle mapView:(MGLMapView *)mapView;
@property (nonatomic, readonly, weak) MGLMapView *mapView;
+@property (nonatomic, readonly) mbgl::style::Style *rawStyle;
- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h
index b6c6372324..ffb95dfc73 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.h
+++ b/platform/darwin/src/MGLSymbolStyleLayer.h
@@ -8,6 +8,72 @@
NS_ASSUME_NONNULL_BEGIN
/**
+ Part of the icon placed closest to the anchor.
+
+ Values of this type are used in the `MGLSymbolStyleLayer.iconAnchor`
+ property.
+ */
+typedef NS_ENUM(NSUInteger, MGLIconAnchor) {
+ /**
+ The center of the icon is placed closest to the anchor.
+ */
+ MGLIconAnchorCenter,
+ /**
+ The left side of the icon is placed closest to the anchor.
+ */
+ MGLIconAnchorLeft,
+ /**
+ The right side of the icon is placed closest to the anchor.
+ */
+ MGLIconAnchorRight,
+ /**
+ The top of the icon is placed closest to the anchor.
+ */
+ MGLIconAnchorTop,
+ /**
+ The bottom of the icon is placed closest to the anchor.
+ */
+ MGLIconAnchorBottom,
+ /**
+ The top left corner of the icon is placed closest to the anchor.
+ */
+ MGLIconAnchorTopLeft,
+ /**
+ The top right corner of the icon is placed closest to the anchor.
+ */
+ MGLIconAnchorTopRight,
+ /**
+ The bottom left corner of the icon is placed closest to the anchor.
+ */
+ MGLIconAnchorBottomLeft,
+ /**
+ The bottom right corner of the icon is placed closest to the anchor.
+ */
+ MGLIconAnchorBottomRight,
+};
+
+/**
+ Orientation of icon when map is pitched.
+
+ Values of this type are used in the `MGLSymbolStyleLayer.iconPitchAlignment`
+ property.
+ */
+typedef NS_ENUM(NSUInteger, MGLIconPitchAlignment) {
+ /**
+ The icon is aligned to the plane of the map.
+ */
+ MGLIconPitchAlignmentMap,
+ /**
+ The icon is aligned to the plane of the viewport.
+ */
+ MGLIconPitchAlignmentViewport,
+ /**
+ Automatically matches the value of `iconRotationAlignment`.
+ */
+ MGLIconPitchAlignmentAuto,
+};
+
+/**
In combination with `symbolPlacement`, determines the rotation behavior of
icons.
@@ -324,6 +390,34 @@ MGL_EXPORT
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconAllowOverlap __attribute__((unavailable("Use iconAllowsOverlap instead.")));
/**
+ Part of the icon placed closest to the anchor.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLIconAnchorCenter`. Set this property to `nil`
+ to reset it to the default value.
+
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLConstantStyleValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconAnchor;
+
+/**
If true, other symbols can be visible even if they collide with the icon.
The default value of this property is an `MGLStyleValue` object containing an
@@ -477,6 +571,24 @@ MGL_EXPORT
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconPadding;
/**
+ Orientation of icon when map is pitched.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLIconPitchAlignmentAuto`. Set this property to
+ `nil` to reset it to the default value.
+
+ This property is only applied to the style if `iconImageName` is non-`nil`.
+ Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLConstantStyleValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconPitchAlignment;
+
+/**
Rotates the icon clockwise.
This property is measured in degrees.
@@ -533,7 +645,11 @@ MGL_EXPORT
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconRotationAlignment;
/**
- Scale factor for icon. 1 is original size, 3 triples the size.
+ Scales the original size of the icon by the provided factor. The new point size
+ of the image will be the original point size multiplied by `iconSize`. 1 is the
+ original size; 3 triples the size of the image.
+
+ This property is measured in factor of the original icon sizes.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
@@ -741,6 +857,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *maximumTextWidth;
@@ -881,8 +1006,18 @@ MGL_EXPORT
You can set this property to an instance of:
* `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textAnchor;
@@ -1000,8 +1135,18 @@ MGL_EXPORT
You can set this property to an instance of:
* `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textJustification;
@@ -1026,6 +1171,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textLetterSpacing;
@@ -1921,6 +2075,32 @@ MGL_EXPORT
#pragma mark Working with Symbol Style Layer Attribute Values
/**
+ Creates a new value object containing the given `MGLIconAnchor` enumeration.
+
+ @param iconAnchor The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLIconAnchor:(MGLIconAnchor)iconAnchor;
+
+/**
+ The `MGLIconAnchor` enumeration representation of the value.
+ */
+@property (readonly) MGLIconAnchor MGLIconAnchorValue;
+
+/**
+ Creates a new value object containing the given `MGLIconPitchAlignment` enumeration.
+
+ @param iconPitchAlignment The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLIconPitchAlignment:(MGLIconPitchAlignment)iconPitchAlignment;
+
+/**
+ The `MGLIconPitchAlignment` enumeration representation of the value.
+ */
+@property (readonly) MGLIconPitchAlignment MGLIconPitchAlignmentValue;
+
+/**
Creates a new value object containing the given `MGLIconRotationAlignment` enumeration.
@param iconRotationAlignment The value for the new object.
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.mm b/platform/darwin/src/MGLSymbolStyleLayer.mm
index 5a8f8c6084..1990c82669 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.mm
+++ b/platform/darwin/src/MGLSymbolStyleLayer.mm
@@ -13,6 +13,24 @@
namespace mbgl {
+ MBGL_DEFINE_ENUM(MGLIconAnchor, {
+ { MGLIconAnchorCenter, "center" },
+ { MGLIconAnchorLeft, "left" },
+ { MGLIconAnchorRight, "right" },
+ { MGLIconAnchorTop, "top" },
+ { MGLIconAnchorBottom, "bottom" },
+ { MGLIconAnchorTopLeft, "top-left" },
+ { MGLIconAnchorTopRight, "top-right" },
+ { MGLIconAnchorBottomLeft, "bottom-left" },
+ { MGLIconAnchorBottomRight, "bottom-right" },
+ });
+
+ MBGL_DEFINE_ENUM(MGLIconPitchAlignment, {
+ { MGLIconPitchAlignmentMap, "map" },
+ { MGLIconPitchAlignmentViewport, "viewport" },
+ { MGLIconPitchAlignmentAuto, "auto" },
+ });
+
MBGL_DEFINE_ENUM(MGLIconRotationAlignment, {
{ MGLIconRotationAlignmentMap, "map" },
{ MGLIconRotationAlignmentViewport, "viewport" },
@@ -160,6 +178,23 @@ namespace mbgl {
return self.iconAllowsOverlap;
}
+- (void)setIconAnchor:(MGLStyleValue<NSValue *> *)iconAnchor {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLIconAnchor>().toDataDrivenPropertyValue(iconAnchor);
+ self.rawLayer->setIconAnchor(mbglValue);
+}
+
+- (MGLStyleValue<NSValue *> *)iconAnchor {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getIconAnchor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLIconAnchor>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconAnchor());
+ }
+ return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLIconAnchor>().toDataDrivenStyleValue(propertyValue);
+}
+
- (void)setIconIgnoresPlacement:(MGLStyleValue<NSNumber *> *)iconIgnoresPlacement {
MGLAssertStyleLayerIsValid();
@@ -259,6 +294,23 @@ namespace mbgl {
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
+- (void)setIconPitchAlignment:(MGLStyleValue<NSValue *> *)iconPitchAlignment {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconPitchAlignment>().toEnumPropertyValue(iconPitchAlignment);
+ self.rawLayer->setIconPitchAlignment(mbglValue);
+}
+
+- (MGLStyleValue<NSValue *> *)iconPitchAlignment {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getIconPitchAlignment();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconPitchAlignment>().toEnumStyleValue(self.rawLayer->getDefaultIconPitchAlignment());
+ }
+ return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconPitchAlignment>().toEnumStyleValue(propertyValue);
+}
+
- (void)setIconRotation:(MGLStyleValue<NSNumber *> *)iconRotation {
MGLAssertStyleLayerIsValid();
@@ -433,7 +485,7 @@ namespace mbgl {
- (void)setMaximumTextWidth:(MGLStyleValue<NSNumber *> *)maximumTextWidth {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(maximumTextWidth);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(maximumTextWidth);
self.rawLayer->setTextMaxWidth(mbglValue);
}
@@ -442,9 +494,9 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getTextMaxWidth();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextMaxWidth());
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextMaxWidth());
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextMaxWidth:(MGLStyleValue<NSNumber *> *)textMaxWidth {
@@ -563,7 +615,7 @@ namespace mbgl {
- (void)setTextAnchor:(MGLStyleValue<NSValue *> *)textAnchor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::TextAnchorType, NSValue *, mbgl::style::TextAnchorType, MGLTextAnchor>().toEnumPropertyValue(textAnchor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toDataDrivenPropertyValue(textAnchor);
self.rawLayer->setTextAnchor(mbglValue);
}
@@ -572,9 +624,9 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getTextAnchor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::TextAnchorType, NSValue *, mbgl::style::TextAnchorType, MGLTextAnchor>().toEnumStyleValue(self.rawLayer->getDefaultTextAnchor());
+ return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextAnchor());
}
- return MGLStyleValueTransformer<mbgl::style::TextAnchorType, NSValue *, mbgl::style::TextAnchorType, MGLTextAnchor>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextFontNames:(MGLStyleValue<NSArray<NSString *> *> *)textFontNames {
@@ -652,7 +704,7 @@ namespace mbgl {
- (void)setTextJustification:(MGLStyleValue<NSValue *> *)textJustification {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toEnumPropertyValue(textJustification);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toDataDrivenPropertyValue(textJustification);
self.rawLayer->setTextJustify(mbglValue);
}
@@ -661,9 +713,9 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getTextJustify();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toEnumStyleValue(self.rawLayer->getDefaultTextJustify());
+ return MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextJustify());
}
- return MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextJustify:(MGLStyleValue<NSValue *> *)textJustify {
@@ -676,7 +728,7 @@ namespace mbgl {
- (void)setTextLetterSpacing:(MGLStyleValue<NSNumber *> *)textLetterSpacing {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(textLetterSpacing);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(textLetterSpacing);
self.rawLayer->setTextLetterSpacing(mbglValue);
}
@@ -685,9 +737,9 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getTextLetterSpacing();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextLetterSpacing());
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextLetterSpacing());
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextLineHeight:(MGLStyleValue<NSNumber *> *)textLineHeight {
@@ -1321,6 +1373,26 @@ namespace mbgl {
@implementation NSValue (MGLSymbolStyleLayerAdditions)
++ (NSValue *)valueWithMGLIconAnchor:(MGLIconAnchor)iconAnchor {
+ return [NSValue value:&iconAnchor withObjCType:@encode(MGLIconAnchor)];
+}
+
+- (MGLIconAnchor)MGLIconAnchorValue {
+ MGLIconAnchor iconAnchor;
+ [self getValue:&iconAnchor];
+ return iconAnchor;
+}
+
++ (NSValue *)valueWithMGLIconPitchAlignment:(MGLIconPitchAlignment)iconPitchAlignment {
+ return [NSValue value:&iconPitchAlignment withObjCType:@encode(MGLIconPitchAlignment)];
+}
+
+- (MGLIconPitchAlignment)MGLIconPitchAlignmentValue {
+ MGLIconPitchAlignment iconPitchAlignment;
+ [self getValue:&iconPitchAlignment];
+ return iconPitchAlignment;
+}
+
+ (NSValue *)valueWithMGLIconRotationAlignment:(MGLIconRotationAlignment)iconRotationAlignment {
return [NSValue value:&iconRotationAlignment withObjCType:@encode(MGLIconRotationAlignment)];
}
diff --git a/platform/darwin/src/MGLVectorSource.mm b/platform/darwin/src/MGLVectorSource.mm
index 5e9f4f4a6e..b1bda56f2d 100644
--- a/platform/darwin/src/MGLVectorSource.mm
+++ b/platform/darwin/src/MGLVectorSource.mm
@@ -3,12 +3,14 @@
#import "MGLFeature_Private.h"
#import "MGLSource_Private.h"
#import "MGLTileSource_Private.h"
+#import "MGLStyle_Private.h"
#import "MGLMapView_Private.h"
#import "NSPredicate+MGLAdditions.h"
#import "NSURL+MGLAdditions.h"
#include <mbgl/map/map.hpp>
#include <mbgl/style/sources/vector_source.hpp>
+#include <mbgl/renderer/renderer.hpp>
@interface MGLVectorSource ()
@@ -63,7 +65,7 @@
std::vector<mbgl::Feature> features;
if (self.mapView) {
- features = self.mapView.mbglMap->querySourceFeatures(self.rawSource->getID(), { optionalSourceLayerIDs, optionalFilter });
+ features = self.mapView.renderer->querySourceFeatures(self.rawSource->getID(), { optionalSourceLayerIDs, optionalFilter });
}
return MGLFeaturesFromMBGLFeatures(features);
}
diff --git a/platform/darwin/src/NSValue+MGLAdditions.h b/platform/darwin/src/NSValue+MGLAdditions.h
index 0aaa2a337a..f3026a389f 100644
--- a/platform/darwin/src/NSValue+MGLAdditions.h
+++ b/platform/darwin/src/NSValue+MGLAdditions.h
@@ -56,6 +56,20 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (readonly) MGLCoordinateBounds MGLCoordinateBoundsValue;
+/**
+ Creates a new value object containing the specified Mapbox coordinate
+ quad structure.
+
+ @param quad The value for the new object.
+ @return A new value object that contains the coordinate quad information.
+ */
++ (instancetype)valueWithMGLCoordinateQuad:(MGLCoordinateQuad)quad;
+
+/**
+ The Mapbox coordinate quad structure representation of the value.
+ */
+- (MGLCoordinateQuad)MGLCoordinateQuadValue;
+
#pragma mark Working with Offline Map Values
/**
diff --git a/platform/darwin/src/NSValue+MGLAdditions.m b/platform/darwin/src/NSValue+MGLAdditions.m
index ef894f0eb4..1383056944 100644
--- a/platform/darwin/src/NSValue+MGLAdditions.m
+++ b/platform/darwin/src/NSValue+MGLAdditions.m
@@ -34,6 +34,16 @@
return bounds;
}
++ (instancetype)valueWithMGLCoordinateQuad:(MGLCoordinateQuad)quad {
+ return [self valueWithBytes:&quad objCType:@encode(MGLCoordinateQuad)];
+}
+
+- (MGLCoordinateQuad)MGLCoordinateQuadValue {
+ MGLCoordinateQuad quad;
+ [self getValue:&quad];
+ return quad;
+}
+
#pragma mark Offline maps
+ (NSValue *)valueWithMGLOfflinePackProgress:(MGLOfflinePackProgress)progress {
diff --git a/platform/darwin/src/headless_backend_cgl.cpp b/platform/darwin/src/headless_backend_cgl.cpp
index 6ad98f4326..3b0c3aaf35 100644
--- a/platform/darwin/src/headless_backend_cgl.cpp
+++ b/platform/darwin/src/headless_backend_cgl.cpp
@@ -51,7 +51,7 @@ gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) {
bool HeadlessBackend::hasDisplay() {
if (!display) {
- display.reset(new HeadlessDisplay);
+ display = HeadlessDisplay::create();
}
return bool(display);
}
diff --git a/platform/darwin/src/http_file_source.mm b/platform/darwin/src/http_file_source.mm
index 649cebb47f..4a16ad82fb 100644
--- a/platform/darwin/src/http_file_source.mm
+++ b/platform/darwin/src/http_file_source.mm
@@ -266,7 +266,9 @@ std::unique_ptr<AsyncRequest> HTTPFileSource::request(const Resource& resource,
NSDictionary *headers = [(NSHTTPURLResponse *)res allHeaderFields];
NSString *cache_control = [headers objectForKey:@"Cache-Control"];
if (cache_control) {
- response.expires = http::CacheControl::parse([cache_control UTF8String]).toTimePoint();
+ const auto cc = http::CacheControl::parse([cache_control UTF8String]);
+ response.expires = cc.toTimePoint();
+ response.mustRevalidate = cc.mustRevalidate;
}
NSString *expires = [headers objectForKey:@"Expires"];
diff --git a/platform/darwin/src/nsthread.mm b/platform/darwin/src/nsthread.mm
index 6caa1be43e..458db968d8 100644
--- a/platform/darwin/src/nsthread.mm
+++ b/platform/darwin/src/nsthread.mm
@@ -15,7 +15,8 @@ std::string getCurrentThreadName() {
}
void setCurrentThreadName(const std::string& name) {
- pthread_setname_np(name.c_str());
+ std::string qualifiedName = "com.mapbox.mbgl." + name;
+ pthread_setname_np(qualifiedName.c_str());
}
void makeThreadLowPriority() {
diff --git a/platform/darwin/src/run_loop.cpp b/platform/darwin/src/run_loop.cpp
index bae8164ab6..2ba8f8415b 100644
--- a/platform/darwin/src/run_loop.cpp
+++ b/platform/darwin/src/run_loop.cpp
@@ -1,38 +1,32 @@
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/async_task.hpp>
-#include <mbgl/util/thread_local.hpp>
+#include <mbgl/actor/scheduler.hpp>
#include <CoreFoundation/CoreFoundation.h>
namespace mbgl {
namespace util {
-// Use a static function to avoid the static initialization order fiasco.
-static auto& current() {
- static ThreadLocal<RunLoop> tl;
- return tl;
-};
-
class RunLoop::Impl {
public:
std::unique_ptr<AsyncTask> async;
};
RunLoop* RunLoop::Get() {
- assert(current().get());
- return current().get();
+ assert(static_cast<RunLoop*>(Scheduler::GetCurrent()));
+ return static_cast<RunLoop*>(Scheduler::GetCurrent());
}
RunLoop::RunLoop(Type)
: impl(std::make_unique<Impl>()) {
- assert(!current().get());
- current().set(this);
+ assert(!Scheduler::GetCurrent());
+ Scheduler::SetCurrent(this);
impl->async = std::make_unique<AsyncTask>(std::bind(&RunLoop::process, this));
}
RunLoop::~RunLoop() {
- assert(current().get());
- current().set(nullptr);
+ assert(Scheduler::GetCurrent());
+ Scheduler::SetCurrent(nullptr);
}
void RunLoop::push(std::shared_ptr<WorkTask> task) {
diff --git a/platform/darwin/test/MGLCircleStyleLayerTests.mm b/platform/darwin/test/MGLCircleStyleLayerTests.mm
index 2a2e9f2d4a..c0c503153a 100644
--- a/platform/darwin/test/MGLCircleStyleLayerTests.mm
+++ b/platform/darwin/test/MGLCircleStyleLayerTests.mm
@@ -246,6 +246,45 @@
XCTAssertEqual(circleOpacityTransition.duration, transitionTest.duration);
}
+ // circle-pitch-alignment
+ {
+ XCTAssertTrue(rawLayer->getCirclePitchAlignment().isUndefined(),
+ @"circle-pitch-alignment should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.circlePitchAlignment;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLCirclePitchAlignment:MGLCirclePitchAlignmentViewport]];
+ layer.circlePitchAlignment = constantStyleValue;
+ mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Viewport };
+ XCTAssertEqual(rawLayer->getCirclePitchAlignment(), propertyValue,
+ @"Setting circlePitchAlignment to a constant value should update circle-pitch-alignment.");
+ XCTAssertEqualObjects(layer.circlePitchAlignment, constantStyleValue,
+ @"circlePitchAlignment should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.circlePitchAlignment = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = { {{18, mbgl::style::AlignmentType::Viewport}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getCirclePitchAlignment(), propertyValue,
+ @"Setting circlePitchAlignment to a camera function should update circle-pitch-alignment.");
+ XCTAssertEqualObjects(layer.circlePitchAlignment, functionStyleValue,
+ @"circlePitchAlignment should round-trip camera functions.");
+
+
+
+ layer.circlePitchAlignment = nil;
+ XCTAssertTrue(rawLayer->getCirclePitchAlignment().isUndefined(),
+ @"Unsetting circlePitchAlignment should return circle-pitch-alignment to the default value.");
+ XCTAssertEqualObjects(layer.circlePitchAlignment, defaultStyleValue,
+ @"circlePitchAlignment should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.circlePitchAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.circlePitchAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ }
+
// circle-radius
{
XCTAssertTrue(rawLayer->getCircleRadius().isUndefined(),
@@ -638,6 +677,7 @@
[self testPropertyName:@"circle-blur" isBoolean:NO];
[self testPropertyName:@"circle-color" isBoolean:NO];
[self testPropertyName:@"circle-opacity" isBoolean:NO];
+ [self testPropertyName:@"circle-pitch-alignment" isBoolean:NO];
[self testPropertyName:@"circle-radius" isBoolean:NO];
[self testPropertyName:@"circle-scale-alignment" isBoolean:NO];
[self testPropertyName:@"circle-stroke-color" isBoolean:NO];
@@ -648,6 +688,8 @@
}
- (void)testValueAdditions {
+ XCTAssertEqual([NSValue valueWithMGLCirclePitchAlignment:MGLCirclePitchAlignmentMap].MGLCirclePitchAlignmentValue, MGLCirclePitchAlignmentMap);
+ XCTAssertEqual([NSValue valueWithMGLCirclePitchAlignment:MGLCirclePitchAlignmentViewport].MGLCirclePitchAlignmentValue, MGLCirclePitchAlignmentViewport);
XCTAssertEqual([NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentMap].MGLCircleScaleAlignmentValue, MGLCircleScaleAlignmentMap);
XCTAssertEqual([NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentViewport].MGLCircleScaleAlignmentValue, MGLCircleScaleAlignmentViewport);
XCTAssertEqual([NSValue valueWithMGLCircleTranslationAnchor:MGLCircleTranslationAnchorMap].MGLCircleTranslationAnchorValue, MGLCircleTranslationAnchorMap);
diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift
index 3e949b0967..42c656f203 100644
--- a/platform/darwin/test/MGLDocumentationExampleTests.swift
+++ b/platform/darwin/test/MGLDocumentationExampleTests.swift
@@ -116,6 +116,20 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
XCTAssertNotNil(polyline)
}
+ func testMGLImageSource() {
+ //#-example-code
+ let coordinates = MGLCoordinateQuad(
+ topLeft: CLLocationCoordinate2D(latitude: 46.437, longitude: -80.425),
+ bottomLeft: CLLocationCoordinate2D(latitude: 37.936, longitude: -80.425),
+ bottomRight: CLLocationCoordinate2D(latitude: 37.936, longitude: -71.516),
+ topRight: CLLocationCoordinate2D(latitude: 46.437, longitude: -71.516))
+ let source = MGLImageSource(identifier: "radar", coordinateQuad: coordinates, url: URL(string: "https://www.mapbox.com/mapbox-gl-js/assets/radar.gif")!)
+ mapView.style?.addSource(source)
+ //#-end-example-code
+
+ XCTAssertNotNil(mapView.style?.source(withIdentifier: "radar"))
+ }
+
func testMGLCircleStyleLayer() {
let population = MGLVectorSource(identifier: "population", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style?.addSource(population)
diff --git a/platform/darwin/test/MGLGeometryTests.mm b/platform/darwin/test/MGLGeometryTests.mm
index 220a837643..1c85470188 100644
--- a/platform/darwin/test/MGLGeometryTests.mm
+++ b/platform/darwin/test/MGLGeometryTests.mm
@@ -144,4 +144,23 @@
XCTAssertEqualObjects(serializedGeoJSON, geoJSON, @"MGLPointFeature should serialize as a GeoJSON point feature.");
}
+- (void)testMGLCoordinateBoundsToMGLCoordinateQuad {
+ MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(37.936, -80.425),
+ CLLocationCoordinate2DMake(46.437, -71.516));
+
+ MGLCoordinateQuad quad = MGLCoordinateQuadFromCoordinateBounds(bounds);
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:bounds.sw],
+ [NSValue valueWithMGLCoordinate:quad.bottomLeft],
+ @"Bounds southwest should be bottom left of quad.");
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:bounds.ne],
+ [NSValue valueWithMGLCoordinate:quad.topRight],
+ @"Bounds northeast should be top right of quad.");
+
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(46.437, -80.425)],
+ [NSValue valueWithMGLCoordinate:quad.topLeft],
+ @"Quad top left should be computed correctly.");
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(37.936, -71.516)],
+ [NSValue valueWithMGLCoordinate:quad.bottomRight],
+ @"Quad bottom right should be computed correctly.");
+}
@end
diff --git a/platform/darwin/test/MGLImageSourceTests.m b/platform/darwin/test/MGLImageSourceTests.m
new file mode 100644
index 0000000000..38fcd38709
--- /dev/null
+++ b/platform/darwin/test/MGLImageSourceTests.m
@@ -0,0 +1,42 @@
+#import <XCTest/XCTest.h>
+
+#import <Mapbox/Mapbox.h>
+
+@interface MGLImageSourceTests : XCTestCase
+
+@end
+
+@implementation MGLImageSourceTests
+
+
+- (void)testMGLImageSourceWithImageURL {
+
+ MGLCoordinateQuad quad = { { 80, 37}, { 81, 37}, { 81, 39}, { 80, 39}};
+ MGLImageSource *source = [[MGLImageSource alloc] initWithIdentifier:@"source-id" coordinateQuad:quad URL:[NSURL URLWithString:@"http://host/image.png"]];
+
+ XCTAssertNotNil(source.URL);
+ XCTAssertEqualObjects(source.URL.absoluteString, @"http://host/image.png");
+ XCTAssertNil(source.image);
+}
+
+- (void)testMGLImageSourceWithImage {
+
+ NSString *imageName = @"RadarImage";
+#if TARGET_OS_IPHONE
+ MGLImage *image = [MGLImage imageNamed:imageName
+ inBundle:[NSBundle bundleForClass:[self class]]
+ compatibleWithTraitCollection:nil];
+#else
+ MGLImage *image = [[NSBundle bundleForClass:[self class]] imageForResource:imageName];
+#endif
+ XCTAssertNotNil(image);
+
+ MGLCoordinateQuad quad = { { 80, 37}, { 81, 37}, { 81, 39}, { 80, 39}};
+ MGLImageSource *source = [[MGLImageSource alloc] initWithIdentifier:@"source-id" coordinateQuad:quad image:image];
+
+ XCTAssertNotNil(source.image);
+ XCTAssertEqualObjects(source.image, image);
+ XCTAssertNil(source.URL);
+}
+
+@end
diff --git a/platform/darwin/test/MGLLightTest.mm b/platform/darwin/test/MGLLightTest.mm
index 8f901cbb72..de64d57851 100644
--- a/platform/darwin/test/MGLLightTest.mm
+++ b/platform/darwin/test/MGLLightTest.mm
@@ -18,7 +18,7 @@
@implementation MGLLightTest
- (void)testProperties {
-
+
MGLTransition defaultTransition = MGLTransitionMake(0, 0);
MGLTransition transition = MGLTransitionMake(6, 3);
mbgl::style::TransitionOptions transitionOptions { { MGLDurationFromTimeInterval(6) }, { MGLDurationFromTimeInterval(3) } };
@@ -35,9 +35,7 @@
XCTAssertEqual(anchorValue.MGLLightAnchorValue, MGLLightAnchorViewport);
mbgl::style::PropertyValue<mbgl::style::LightAnchorType> propertyValue = { mbgl::style::LightAnchorType::Viewport };
-
light.setAnchor(propertyValue);
-
mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
lightFromMGLlight = [mglLight mbglLight];
@@ -55,14 +53,12 @@
XCTAssert(positionTransition.delay && MGLTimeIntervalFromDuration(*positionTransition.delay) == defaultTransition.delay);
XCTAssert(positionTransition.duration && MGLTimeIntervalFromDuration(*positionTransition.duration) == defaultTransition.duration);
- const std::array<float, 3> positionArray = { { 6, 180, 90 } };
+ std::array<float, 3> positionArray = { { 6, 180, 90 } };
mbgl::style::Position position = { positionArray };
mbgl::style::PropertyValue<mbgl::style::Position> propertyValue = { position };
-
light.setPosition(propertyValue);
light.setPositionTransition(transitionOptions);
-
mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
lightFromMGLlight = [mglLight mbglLight];
@@ -85,11 +81,9 @@
XCTAssert(colorTransition.duration && MGLTimeIntervalFromDuration(*colorTransition.duration) == defaultTransition.duration);
mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
-
light.setColor(propertyValue);
light.setColorTransition(transitionOptions);
-
mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
lightFromMGLlight = [mglLight mbglLight];
@@ -112,11 +106,9 @@
XCTAssert(intensityTransition.duration && MGLTimeIntervalFromDuration(*intensityTransition.duration) == defaultTransition.duration);
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
-
light.setIntensity(propertyValue);
light.setIntensityTransition(transitionOptions);
-
mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
lightFromMGLlight = [mglLight mbglLight];
@@ -131,10 +123,10 @@
- (void)testValueAdditions {
MGLSphericalPosition position = MGLSphericalPositionMake(1.15, 210, 30);
-
- XCTAssertEqual(@(position).MGLSphericalPositionValue.radial, position.radial);
- XCTAssertEqual(@(position).MGLSphericalPositionValue.azimuthal, position.azimuthal);
- XCTAssertEqual(@(position).MGLSphericalPositionValue.polar, position.polar);
+
+ XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.radial, position.radial);
+ XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.azimuthal, position.azimuthal);
+ XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.polar, position.polar);
XCTAssertEqual([NSValue valueWithMGLLightAnchor:MGLLightAnchorMap].MGLLightAnchorValue, MGLLightAnchorMap);
XCTAssertEqual([NSValue valueWithMGLLightAnchor:MGLLightAnchorViewport].MGLLightAnchorValue, MGLLightAnchorViewport);
}
diff --git a/platform/darwin/test/MGLLightTest.mm.ejs b/platform/darwin/test/MGLLightTest.mm.ejs
index c1904d5ab8..5b1f27d8d1 100644
--- a/platform/darwin/test/MGLLightTest.mm.ejs
+++ b/platform/darwin/test/MGLLightTest.mm.ejs
@@ -22,7 +22,7 @@
@implementation MGLLightTest
- (void)testProperties {
-
+
MGLTransition defaultTransition = MGLTransitionMake(0, 0);
MGLTransition transition = MGLTransitionMake(6, 3);
mbgl::style::TransitionOptions transitionOptions { { MGLDurationFromTimeInterval(6) }, { MGLDurationFromTimeInterval(3) } };
@@ -48,17 +48,17 @@
<% } -%>
<% if (property.type == "array") { -%>
- const std::array<float, 3> positionArray = { { 6, 180, 90 } };
+ std::array<float, 3> positionArray = { { 6, 180, 90 } };
mbgl::style::Position position = { positionArray };
mbgl::style::PropertyValue<mbgl::style::Position> propertyValue = { position };
<% } else { -%>
mbgl::style::PropertyValue<<%- mbglType(property) %>> propertyValue = { <%- mbglTestValue(property, type) %> };
-<% } -%>
+<% } -%>
light.set<%- camelize(property.name) -%>(propertyValue);
<% if (property.transition) { -%>
light.set<%- camelize(property.name) -%>Transition(transitionOptions);
-<% } -%>
+<% } -%>
mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
lightFromMGLlight = [mglLight mbglLight];
@@ -76,7 +76,7 @@
- (void)testValueAdditions {
MGLSphericalPosition position = MGLSphericalPositionMake(1.15, 210, 30);
-
+
XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.radial, position.radial);
XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.azimuthal, position.azimuthal);
XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.polar, position.polar);
diff --git a/platform/darwin/test/MGLLineStyleLayerTests.mm b/platform/darwin/test/MGLLineStyleLayerTests.mm
index 1e92959520..7e7926e22e 100644
--- a/platform/darwin/test/MGLLineStyleLayerTests.mm
+++ b/platform/darwin/test/MGLLineStyleLayerTests.mm
@@ -95,7 +95,7 @@
MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineJoin:MGLLineJoinMiter]];
layer.lineJoin = constantStyleValue;
- mbgl::style::PropertyValue<mbgl::style::LineJoinType> propertyValue = { mbgl::style::LineJoinType::Miter };
+ mbgl::style::DataDrivenPropertyValue<mbgl::style::LineJoinType> propertyValue = { mbgl::style::LineJoinType::Miter };
XCTAssertEqual(rawLayer->getLineJoin(), propertyValue,
@"Setting lineJoin to a constant value should update line-join.");
XCTAssertEqualObjects(layer.lineJoin, constantStyleValue,
@@ -119,11 +119,6 @@
@"Unsetting lineJoin should return line-join to the default value.");
XCTAssertEqualObjects(layer.lineJoin, defaultStyleValue,
@"lineJoin should return the default value after being unset.");
-
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineJoin = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineJoin = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// line-miter-limit
@@ -713,7 +708,7 @@
MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.lineWidth = constantStyleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
@"Setting lineWidth to a constant value should update line-width.");
XCTAssertEqualObjects(layer.lineWidth, constantStyleValue,
@@ -730,6 +725,29 @@
XCTAssertEqualObjects(layer.lineWidth, functionStyleValue,
@"lineWidth should round-trip camera functions.");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.lineWidth = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
+ @"Setting lineWidth to a source function should update line-width.");
+ XCTAssertEqualObjects(layer.lineWidth, functionStyleValue,
+ @"lineWidth should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.lineWidth = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
+ @"Setting lineWidth to a composite function should update line-width.");
+ XCTAssertEqualObjects(layer.lineWidth, functionStyleValue,
+ @"lineWidth should round-trip composite functions.");
layer.lineWidth = nil;
@@ -737,11 +755,6 @@
@"Unsetting lineWidth should return line-width to the default value.");
XCTAssertEqualObjects(layer.lineWidth, defaultStyleValue,
@"lineWidth should return the default value after being unset.");
-
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineWidth = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineWidth = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
// Transition property test
layer.lineWidthTransition = transitionTest;
auto toptions = rawLayer->getLineWidthTransition();
diff --git a/platform/darwin/test/MGLStyleTests.mm b/platform/darwin/test/MGLStyleTests.mm
index 0814ceda2d..8f610e338c 100644
--- a/platform/darwin/test/MGLStyleTests.mm
+++ b/platform/darwin/test/MGLStyleTests.mm
@@ -213,9 +213,9 @@
MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
[self.style addSource:rasterSource];
- // Attempt to remove a shape source with the same identifier as the raster source
- MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"some-identifier" shape:nil options:nil];
- [self.style removeSource:shapeSource];
+ // Attempt to remove an image source with the same identifier as the raster source
+ MGLImageSource *imageSource = [[MGLImageSource alloc] initWithIdentifier:@"some-identifier" coordinateQuad: { } URL:[NSURL URLWithString:@"http://host/image.png"]];
+ [self.style removeSource:imageSource];
// The raster source should still be added
XCTAssertTrue([[self.style sourceWithIdentifier:rasterSource.identifier] isMemberOfClass:[MGLRasterSource class]]);
@@ -223,16 +223,16 @@
[self.style removeSource:rasterSource];
// Add the shape source
- [self.style addSource:shapeSource];
+ [self.style addSource:imageSource];
// Attempt to remove a vector source with the same identifer as the shape source
MGLVectorSource *vectorSource = [[MGLVectorSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
[self.style removeSource:vectorSource];
- // The shape source should still be added
- XCTAssertTrue([[self.style sourceWithIdentifier:shapeSource.identifier] isMemberOfClass:[MGLShapeSource class]]);
+ // The image source should still be added
+ XCTAssertTrue([[self.style sourceWithIdentifier:imageSource.identifier] isMemberOfClass:[MGLImageSource class]]);
- // Remove the shape source
- [self.style removeSource:shapeSource];
+ // Remove the image source
+ [self.style removeSource:imageSource];
// Add the vector source
[self.style addSource:vectorSource];
@@ -240,7 +240,7 @@
// Attempt to remove the previously created raster source that has the same identifer as the shape source
[self.style removeSource:rasterSource];
// The vector source should still be added
- XCTAssertTrue([[self.style sourceWithIdentifier:shapeSource.identifier] isMemberOfClass:[MGLVectorSource class]]);
+ XCTAssertTrue([[self.style sourceWithIdentifier:imageSource.identifier] isMemberOfClass:[MGLVectorSource class]]);
}
- (void)testRemovingSourceInUse {
diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.mm b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
index 367ebf363c..1ac86dd402 100644
--- a/platform/darwin/test/MGLSymbolStyleLayerTests.mm
+++ b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
@@ -87,6 +87,40 @@
XCTAssertThrowsSpecificNamed(layer.iconAllowsOverlap = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
+ // icon-anchor
+ {
+ XCTAssertTrue(rawLayer->getIconAnchor().isUndefined(),
+ @"icon-anchor should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconAnchor;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconAnchor:MGLIconAnchorBottomRight]];
+ layer.iconAnchor = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<mbgl::style::SymbolAnchorType> propertyValue = { mbgl::style::SymbolAnchorType::BottomRight };
+ XCTAssertEqual(rawLayer->getIconAnchor(), propertyValue,
+ @"Setting iconAnchor to a constant value should update icon-anchor.");
+ XCTAssertEqualObjects(layer.iconAnchor, constantStyleValue,
+ @"iconAnchor should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconAnchor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::SymbolAnchorType> intervalStops = { {{18, mbgl::style::SymbolAnchorType::BottomRight}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::SymbolAnchorType> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getIconAnchor(), propertyValue,
+ @"Setting iconAnchor to a camera function should update icon-anchor.");
+ XCTAssertEqualObjects(layer.iconAnchor, functionStyleValue,
+ @"iconAnchor should round-trip camera functions.");
+
+
+
+ layer.iconAnchor = nil;
+ XCTAssertTrue(rawLayer->getIconAnchor().isUndefined(),
+ @"Unsetting iconAnchor should return icon-anchor to the default value.");
+ XCTAssertEqualObjects(layer.iconAnchor, defaultStyleValue,
+ @"iconAnchor should return the default value after being unset.");
+ }
+
// icon-ignore-placement
{
XCTAssertTrue(rawLayer->getIconIgnorePlacement().isUndefined(),
@@ -301,6 +335,45 @@
XCTAssertThrowsSpecificNamed(layer.iconPadding = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
+ // icon-pitch-alignment
+ {
+ XCTAssertTrue(rawLayer->getIconPitchAlignment().isUndefined(),
+ @"icon-pitch-alignment should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconPitchAlignment;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconPitchAlignment:MGLIconPitchAlignmentAuto]];
+ layer.iconPitchAlignment = constantStyleValue;
+ mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Auto };
+ XCTAssertEqual(rawLayer->getIconPitchAlignment(), propertyValue,
+ @"Setting iconPitchAlignment to a constant value should update icon-pitch-alignment.");
+ XCTAssertEqualObjects(layer.iconPitchAlignment, constantStyleValue,
+ @"iconPitchAlignment should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconPitchAlignment = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = { {{18, mbgl::style::AlignmentType::Auto}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getIconPitchAlignment(), propertyValue,
+ @"Setting iconPitchAlignment to a camera function should update icon-pitch-alignment.");
+ XCTAssertEqualObjects(layer.iconPitchAlignment, functionStyleValue,
+ @"iconPitchAlignment should round-trip camera functions.");
+
+
+
+ layer.iconPitchAlignment = nil;
+ XCTAssertTrue(rawLayer->getIconPitchAlignment().isUndefined(),
+ @"Unsetting iconPitchAlignment should return icon-pitch-alignment to the default value.");
+ XCTAssertEqualObjects(layer.iconPitchAlignment, defaultStyleValue,
+ @"iconPitchAlignment should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconPitchAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconPitchAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ }
+
// icon-rotate
{
XCTAssertTrue(rawLayer->getIconRotate().isUndefined(),
@@ -663,7 +736,7 @@
MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.maximumTextWidth = constantStyleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue,
@"Setting maximumTextWidth to a constant value should update text-max-width.");
XCTAssertEqualObjects(layer.maximumTextWidth, constantStyleValue,
@@ -680,6 +753,29 @@
XCTAssertEqualObjects(layer.maximumTextWidth, functionStyleValue,
@"maximumTextWidth should round-trip camera functions.");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.maximumTextWidth = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue,
+ @"Setting maximumTextWidth to a source function should update text-max-width.");
+ XCTAssertEqualObjects(layer.maximumTextWidth, functionStyleValue,
+ @"maximumTextWidth should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.maximumTextWidth = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue,
+ @"Setting maximumTextWidth to a composite function should update text-max-width.");
+ XCTAssertEqualObjects(layer.maximumTextWidth, functionStyleValue,
+ @"maximumTextWidth should round-trip composite functions.");
layer.maximumTextWidth = nil;
@@ -687,11 +783,6 @@
@"Unsetting maximumTextWidth should return text-max-width to the default value.");
XCTAssertEqualObjects(layer.maximumTextWidth, defaultStyleValue,
@"maximumTextWidth should return the default value after being unset.");
-
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.maximumTextWidth = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.maximumTextWidth = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// symbol-avoid-edges
@@ -892,7 +983,7 @@
MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomRight]];
layer.textAnchor = constantStyleValue;
- mbgl::style::PropertyValue<mbgl::style::TextAnchorType> propertyValue = { mbgl::style::TextAnchorType::BottomRight };
+ mbgl::style::DataDrivenPropertyValue<mbgl::style::SymbolAnchorType> propertyValue = { mbgl::style::SymbolAnchorType::BottomRight };
XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue,
@"Setting textAnchor to a constant value should update text-anchor.");
XCTAssertEqualObjects(layer.textAnchor, constantStyleValue,
@@ -901,8 +992,8 @@
MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
layer.textAnchor = functionStyleValue;
- mbgl::style::IntervalStops<mbgl::style::TextAnchorType> intervalStops = { {{18, mbgl::style::TextAnchorType::BottomRight}} };
- propertyValue = mbgl::style::CameraFunction<mbgl::style::TextAnchorType> { intervalStops };
+ mbgl::style::IntervalStops<mbgl::style::SymbolAnchorType> intervalStops = { {{18, mbgl::style::SymbolAnchorType::BottomRight}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::SymbolAnchorType> { intervalStops };
XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue,
@"Setting textAnchor to a camera function should update text-anchor.");
@@ -916,11 +1007,6 @@
@"Unsetting textAnchor should return text-anchor to the default value.");
XCTAssertEqualObjects(layer.textAnchor, defaultStyleValue,
@"textAnchor should return the default value after being unset.");
-
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// text-font
@@ -1066,7 +1152,7 @@
MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextJustification:MGLTextJustificationRight]];
layer.textJustification = constantStyleValue;
- mbgl::style::PropertyValue<mbgl::style::TextJustifyType> propertyValue = { mbgl::style::TextJustifyType::Right };
+ mbgl::style::DataDrivenPropertyValue<mbgl::style::TextJustifyType> propertyValue = { mbgl::style::TextJustifyType::Right };
XCTAssertEqual(rawLayer->getTextJustify(), propertyValue,
@"Setting textJustification to a constant value should update text-justify.");
XCTAssertEqualObjects(layer.textJustification, constantStyleValue,
@@ -1090,11 +1176,6 @@
@"Unsetting textJustification should return text-justify to the default value.");
XCTAssertEqualObjects(layer.textJustification, defaultStyleValue,
@"textJustification should return the default value after being unset.");
-
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textJustification = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textJustification = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// text-letter-spacing
@@ -1105,7 +1186,7 @@
MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.textLetterSpacing = constantStyleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue,
@"Setting textLetterSpacing to a constant value should update text-letter-spacing.");
XCTAssertEqualObjects(layer.textLetterSpacing, constantStyleValue,
@@ -1122,6 +1203,29 @@
XCTAssertEqualObjects(layer.textLetterSpacing, functionStyleValue,
@"textLetterSpacing should round-trip camera functions.");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.textLetterSpacing = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue,
+ @"Setting textLetterSpacing to a source function should update text-letter-spacing.");
+ XCTAssertEqualObjects(layer.textLetterSpacing, functionStyleValue,
+ @"textLetterSpacing should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.textLetterSpacing = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue,
+ @"Setting textLetterSpacing to a composite function should update text-letter-spacing.");
+ XCTAssertEqualObjects(layer.textLetterSpacing, functionStyleValue,
+ @"textLetterSpacing should round-trip composite functions.");
layer.textLetterSpacing = nil;
@@ -1129,11 +1233,6 @@
@"Unsetting textLetterSpacing should return text-letter-spacing to the default value.");
XCTAssertEqualObjects(layer.textLetterSpacing, defaultStyleValue,
@"textLetterSpacing should return the default value after being unset.");
-
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textLetterSpacing = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textLetterSpacing = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// text-line-height
@@ -2316,11 +2415,13 @@
- (void)testPropertyNames {
[self testPropertyName:@"icon-allows-overlap" isBoolean:YES];
+ [self testPropertyName:@"icon-anchor" isBoolean:NO];
[self testPropertyName:@"icon-ignores-placement" isBoolean:YES];
[self testPropertyName:@"icon-image-name" isBoolean:NO];
[self testPropertyName:@"icon-offset" isBoolean:NO];
[self testPropertyName:@"is-icon-optional" isBoolean:YES];
[self testPropertyName:@"icon-padding" isBoolean:NO];
+ [self testPropertyName:@"icon-pitch-alignment" isBoolean:NO];
[self testPropertyName:@"icon-rotation" isBoolean:NO];
[self testPropertyName:@"icon-rotation-alignment" isBoolean:NO];
[self testPropertyName:@"icon-scale" isBoolean:NO];
@@ -2366,6 +2467,18 @@
}
- (void)testValueAdditions {
+ XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorCenter].MGLIconAnchorValue, MGLIconAnchorCenter);
+ XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorLeft].MGLIconAnchorValue, MGLIconAnchorLeft);
+ XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorRight].MGLIconAnchorValue, MGLIconAnchorRight);
+ XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorTop].MGLIconAnchorValue, MGLIconAnchorTop);
+ XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorBottom].MGLIconAnchorValue, MGLIconAnchorBottom);
+ XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorTopLeft].MGLIconAnchorValue, MGLIconAnchorTopLeft);
+ XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorTopRight].MGLIconAnchorValue, MGLIconAnchorTopRight);
+ XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorBottomLeft].MGLIconAnchorValue, MGLIconAnchorBottomLeft);
+ XCTAssertEqual([NSValue valueWithMGLIconAnchor:MGLIconAnchorBottomRight].MGLIconAnchorValue, MGLIconAnchorBottomRight);
+ XCTAssertEqual([NSValue valueWithMGLIconPitchAlignment:MGLIconPitchAlignmentMap].MGLIconPitchAlignmentValue, MGLIconPitchAlignmentMap);
+ XCTAssertEqual([NSValue valueWithMGLIconPitchAlignment:MGLIconPitchAlignmentViewport].MGLIconPitchAlignmentValue, MGLIconPitchAlignmentViewport);
+ XCTAssertEqual([NSValue valueWithMGLIconPitchAlignment:MGLIconPitchAlignmentAuto].MGLIconPitchAlignmentValue, MGLIconPitchAlignmentAuto);
XCTAssertEqual([NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentMap].MGLIconRotationAlignmentValue, MGLIconRotationAlignmentMap);
XCTAssertEqual([NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentViewport].MGLIconRotationAlignmentValue, MGLIconRotationAlignmentViewport);
XCTAssertEqual([NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentAuto].MGLIconRotationAlignmentValue, MGLIconRotationAlignmentAuto);
diff --git a/platform/darwin/test/Media.xcassets/RadarImage.imageset/Contents.json b/platform/darwin/test/Media.xcassets/RadarImage.imageset/Contents.json
new file mode 100644
index 0000000000..79be9ed970
--- /dev/null
+++ b/platform/darwin/test/Media.xcassets/RadarImage.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "radar.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/platform/darwin/test/Media.xcassets/RadarImage.imageset/radar.png b/platform/darwin/test/Media.xcassets/RadarImage.imageset/radar.png
new file mode 100644
index 0000000000..e23697f42a
--- /dev/null
+++ b/platform/darwin/test/Media.xcassets/RadarImage.imageset/radar.png
Binary files differ