summaryrefslogtreecommitdiff
path: root/platform/darwin/src
diff options
context:
space:
mode:
Diffstat (limited to 'platform/darwin/src')
-rw-r--r--platform/darwin/src/MGLAbstractShapeSource.h124
-rw-r--r--platform/darwin/src/MGLAbstractShapeSource.mm136
-rw-r--r--platform/darwin/src/MGLAccountManager.h26
-rw-r--r--platform/darwin/src/MGLAccountManager.m9
-rw-r--r--platform/darwin/src/MGLAccountManager_Private.h2
-rw-r--r--platform/darwin/src/MGLAttributionInfo.mm7
-rw-r--r--platform/darwin/src/MGLBackgroundStyleLayer.h29
-rw-r--r--platform/darwin/src/MGLBackgroundStyleLayer.mm3
-rw-r--r--platform/darwin/src/MGLCircleStyleLayer.h67
-rw-r--r--platform/darwin/src/MGLComputedShapeSource.h70
-rw-r--r--platform/darwin/src/MGLComputedShapeSource.mm60
-rw-r--r--platform/darwin/src/MGLComputedShapeSource_Private.h (renamed from platform/darwin/src/MGLAbstractShapeSource_Private.h)12
-rw-r--r--platform/darwin/src/MGLFeature.h27
-rw-r--r--platform/darwin/src/MGLFillExtrusionStyleLayer.h45
-rw-r--r--platform/darwin/src/MGLFillExtrusionStyleLayer.mm3
-rw-r--r--platform/darwin/src/MGLFillStyleLayer.h54
-rw-r--r--platform/darwin/src/MGLFillStyleLayer.mm3
-rw-r--r--platform/darwin/src/MGLGeometry.h32
-rw-r--r--platform/darwin/src/MGLGeometry.mm16
-rw-r--r--platform/darwin/src/MGLGeometry_Private.h2
-rw-r--r--platform/darwin/src/MGLHeatmapStyleLayer.h58
-rw-r--r--platform/darwin/src/MGLHillshadeStyleLayer.h77
-rw-r--r--platform/darwin/src/MGLLight.h29
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.h56
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.mm3
-rw-r--r--platform/darwin/src/MGLMapSnapshotter.h2
-rw-r--r--platform/darwin/src/MGLNetworkConfiguration.h2
-rw-r--r--platform/darwin/src/MGLOfflineStorage.h10
-rw-r--r--platform/darwin/src/MGLOfflineStorage.mm4
-rw-r--r--platform/darwin/src/MGLOpenGLStyleLayer.h3
-rw-r--r--platform/darwin/src/MGLOpenGLStyleLayer.mm92
-rw-r--r--platform/darwin/src/MGLPointAnnotation.h5
-rw-r--r--platform/darwin/src/MGLPointCollection.h5
-rw-r--r--platform/darwin/src/MGLPolygon.h9
-rw-r--r--platform/darwin/src/MGLPolyline.h9
-rw-r--r--platform/darwin/src/MGLPolyline.mm8
-rw-r--r--platform/darwin/src/MGLRasterDEMSource.h17
-rw-r--r--platform/darwin/src/MGLRasterDEMSource.mm2
-rw-r--r--platform/darwin/src/MGLRasterStyleLayer.h28
-rw-r--r--platform/darwin/src/MGLRasterTileSource.h (renamed from platform/darwin/src/MGLRasterSource.h)45
-rw-r--r--platform/darwin/src/MGLRasterTileSource.mm (renamed from platform/darwin/src/MGLRasterSource.mm)14
-rw-r--r--platform/darwin/src/MGLRasterTileSource_Private.h (renamed from platform/darwin/src/MGLRasterSource_Private.h)4
-rw-r--r--platform/darwin/src/MGLRendererConfiguration.h2
-rw-r--r--platform/darwin/src/MGLShape.h18
-rw-r--r--platform/darwin/src/MGLShapeCollection.h5
-rw-r--r--platform/darwin/src/MGLShapeSource.h131
-rw-r--r--platform/darwin/src/MGLShapeSource.mm69
-rw-r--r--platform/darwin/src/MGLShapeSource_Private.h4
-rw-r--r--platform/darwin/src/MGLSource.h9
-rw-r--r--platform/darwin/src/MGLStyle.h109
-rw-r--r--platform/darwin/src/MGLStyle.mm182
-rw-r--r--platform/darwin/src/MGLStyleLayer.mm.ejs10
-rw-r--r--platform/darwin/src/MGLStyleValue.h14
-rw-r--r--platform/darwin/src/MGLStyleValue.mm87
-rw-r--r--platform/darwin/src/MGLStyleValue_Private.h8
-rw-r--r--platform/darwin/src/MGLStyle_Private.h4
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.h183
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.mm6
-rw-r--r--platform/darwin/src/MGLTileSource.h6
-rw-r--r--platform/darwin/src/MGLTileSource.mm1
-rw-r--r--platform/darwin/src/MGLVectorStyleLayer.h4
-rw-r--r--platform/darwin/src/MGLVectorTileSource.h (renamed from platform/darwin/src/MGLVectorSource.h)41
-rw-r--r--platform/darwin/src/MGLVectorTileSource.mm (renamed from platform/darwin/src/MGLVectorSource.mm)51
-rw-r--r--platform/darwin/src/MGLVectorTileSource_Private.h (renamed from platform/darwin/src/MGLVectorSource_Private.h)7
-rw-r--r--platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm260
-rw-r--r--platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm60
-rw-r--r--platform/darwin/src/NSExpression+MGLAdditions.h160
-rw-r--r--platform/darwin/src/NSExpression+MGLAdditions.mm942
-rw-r--r--platform/darwin/src/NSExpression+MGLPrivateAdditions.h10
-rw-r--r--platform/darwin/src/NSPredicate+MGLAdditions.h4
-rw-r--r--platform/darwin/src/NSPredicate+MGLAdditions.mm109
-rw-r--r--platform/darwin/src/NSString+MGLAdditions.m6
-rw-r--r--platform/darwin/src/NSValue+MGLAdditions.h13
-rw-r--r--platform/darwin/src/NSValue+MGLAdditions.m10
74 files changed, 2384 insertions, 1350 deletions
diff --git a/platform/darwin/src/MGLAbstractShapeSource.h b/platform/darwin/src/MGLAbstractShapeSource.h
deleted file mode 100644
index d61f41fbf6..0000000000
--- a/platform/darwin/src/MGLAbstractShapeSource.h
+++ /dev/null
@@ -1,124 +0,0 @@
-#import "MGLSource.h"
-
-/**
- Options for `MGLShapeSource` objects.
- */
-typedef NSString *MGLShapeSourceOption NS_STRING_ENUM;
-
-/**
- An `NSNumber` object containing a Boolean enabling or disabling clustering.
- If the `shape` property contains point shapes, setting this option to
- `YES` clusters the points by radius into groups. The default value is `NO`.
-
- This attribute corresponds to the
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-cluster"><code>cluster</code></a>
- source property in the Mapbox Style Specification.
-
- This option only affects point features within a shape source.
- */
-extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClustered;
-
-/**
- An `NSNumber` object containing an integer; specifies the radius of each
- cluster if clustering is enabled. A value of 512 produces a radius equal to
- the width of a tile. The default value is 50.
- */
-extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius;
-
-/**
- An `NSNumber` object containing an integer; specifies the maximum zoom level at
- which to cluster points if clustering is enabled. Defaults to one zoom level
- less than the value of `MGLShapeSourceOptionMaximumZoomLevel` so that, at the
- maximum zoom level, the shapes are not clustered.
-
- This attribute corresponds to the
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-clusterMaxZoom"><code>clusterMaxZoom</code></a>
- source property in the Mapbox Style Specification.
- */
-extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering;
-
-/**
- An `NSNumber` object containing an integer; specifies the minimum zoom level at
- which to create vector tiles. The default value is 0.
-
- This attribute corresponds to the
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-minzoom"><code>minzoom</code></a>
- source property in the Mapbox Style Specification.
- */
-extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMinimumZoomLevel;
-
-/**
- An `NSNumber` object containing an integer; specifies the maximum zoom level at
- which to create vector tiles. A greater value produces greater detail at high
- zoom levels. The default value is 18.
-
- This attribute corresponds to the
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-maxzoom"><code>maxzoom</code></a>
- source property in the Mapbox Style Specification.
- */
-extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel;
-
-/**
- An `NSNumber` object containing an integer; specifies the size of the tile
- buffer on each side. A value of 0 produces no buffer. A value of 512 produces a
- buffer as wide as the tile itself. Larger values produce fewer rendering
- artifacts near tile edges and slower performance. The default value is 128.
-
- This attribute corresponds to the
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-buffer"><code>buffer</code></a>
- source property in the Mapbox Style Specification.
- */
-extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionBuffer;
-
-/**
- An `NSNumber` object containing a double; specifies the Douglas-Peucker
- simplification tolerance. A greater value produces simpler geometries and
- improves performance. The default value is 0.375.
-
- This attribute corresponds to the
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-tolerance"><code>tolerance</code></a>
- source property in the Mapbox Style Specification.
- */
-extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance;
-
-/**
- An `NSNumber` object containing a Boolean value; specifies whether the shape of
- an `MGLComputedShapeSource` should be wrapped to accomodate coordinates with
- longitudes beyond −180 and 180. The default value is `NO`.
-
- Setting this option to `YES` affects rendering performance.
-
- This option is ignored when creating an instance of a class besides
- `MGLComputedShapeSource`.
- */
-extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionWrapsCoordinates;
-
-/**
- An `NSNumber` object containing a Boolean value; specifies whether the shape of
- an `MGLComputedShapeSource` should be clipped at the edge of each tile. The
- default value is `NO`.
-
- Setting this option to `YES` affects rendering performance. Use this option to
- clip `MGLPolyline`s and `MGLPolygon`s at tile boundaries without artifacts.
-
- This option is ignored when creating an instance of a class besides
- `MGLComputedShapeSource`.
- */
-extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClipsCoordinates;
-
-/**
- `MGLAbstractShapeSource` is an abstract base class for map content sources that
- supply vector shapes to be shown on the map. A shape source is added to an
- `MGLStyle` object along with an `MGLVectorStyleLayer` object. The vector style
- layer defines the appearance of any content supplied by the shape source.
-
-
- Do not create instances of this class directly, and do not create your own
- subclasses of this class. Instead, create instances of `MGLShapeSource` or
- `MGLComputedShapeSource`.
- */
-MGL_EXPORT
-@interface MGLAbstractShapeSource : MGLSource
-
-
-@end
diff --git a/platform/darwin/src/MGLAbstractShapeSource.mm b/platform/darwin/src/MGLAbstractShapeSource.mm
deleted file mode 100644
index eb0807cee0..0000000000
--- a/platform/darwin/src/MGLAbstractShapeSource.mm
+++ /dev/null
@@ -1,136 +0,0 @@
-#import "MGLAbstractShapeSource.h"
-#import "MGLAbstractShapeSource_Private.h"
-
-const MGLShapeSourceOption MGLShapeSourceOptionBuffer = @"MGLShapeSourceOptionBuffer";
-const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius = @"MGLShapeSourceOptionClusterRadius";
-const MGLShapeSourceOption MGLShapeSourceOptionClustered = @"MGLShapeSourceOptionClustered";
-const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel = @"MGLShapeSourceOptionMaximumZoomLevel";
-const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering = @"MGLShapeSourceOptionMaximumZoomLevelForClustering";
-const MGLShapeSourceOption MGLShapeSourceOptionMinimumZoomLevel = @"MGLShapeSourceOptionMinimumZoomLevel";
-const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLShapeSourceOptionSimplificationTolerance";
-const MGLShapeSourceOption MGLShapeSourceOptionWrapsCoordinates = @"MGLShapeSourceOptionWrapsCoordinates";
-const MGLShapeSourceOption MGLShapeSourceOptionClipsCoordinates = @"MGLShapeSourceOptionClipsCoordinates";
-
-@interface MGLAbstractShapeSource ()
-
-@end
-
-@implementation MGLAbstractShapeSource
-
-@end
-
-mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options) {
- auto geoJSONOptions = mbgl::style::GeoJSONOptions();
-
- if (NSNumber *value = options[MGLShapeSourceOptionMinimumZoomLevel]) {
- if (![value isKindOfClass:[NSNumber class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"MGLShapeSourceOptionMaximumZoomLevel must be an NSNumber."];
- }
- geoJSONOptions.minzoom = value.integerValue;
- }
-
- if (NSNumber *value = options[MGLShapeSourceOptionMaximumZoomLevel]) {
- if (![value isKindOfClass:[NSNumber class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"MGLShapeSourceOptionMaximumZoomLevel must be an NSNumber."];
- }
- geoJSONOptions.maxzoom = value.integerValue;
- }
-
- if (NSNumber *value = options[MGLShapeSourceOptionBuffer]) {
- if (![value isKindOfClass:[NSNumber class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"MGLShapeSourceOptionBuffer must be an NSNumber."];
- }
- geoJSONOptions.buffer = value.integerValue;
- }
-
- if (NSNumber *value = options[MGLShapeSourceOptionSimplificationTolerance]) {
- if (![value isKindOfClass:[NSNumber class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"MGLShapeSourceOptionSimplificationTolerance must be an NSNumber."];
- }
- geoJSONOptions.tolerance = value.doubleValue;
- }
-
- if (NSNumber *value = options[MGLShapeSourceOptionClusterRadius]) {
- if (![value isKindOfClass:[NSNumber class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"MGLShapeSourceOptionClusterRadius must be an NSNumber."];
- }
- geoJSONOptions.clusterRadius = value.integerValue;
- }
-
- if (NSNumber *value = options[MGLShapeSourceOptionMaximumZoomLevelForClustering]) {
- if (![value isKindOfClass:[NSNumber class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"MGLShapeSourceOptionMaximumZoomLevelForClustering must be an NSNumber."];
- }
- geoJSONOptions.clusterMaxZoom = value.integerValue;
- }
-
- if (NSNumber *value = options[MGLShapeSourceOptionClustered]) {
- if (![value isKindOfClass:[NSNumber class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"MGLShapeSourceOptionClustered must be an NSNumber."];
- }
- geoJSONOptions.cluster = value.boolValue;
- }
-
- return geoJSONOptions;
-}
-
-mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options) {
- mbgl::style::CustomGeometrySource::Options sourceOptions;
-
- if (NSNumber *value = options[MGLShapeSourceOptionMinimumZoomLevel]) {
- if (![value isKindOfClass:[NSNumber class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"MGLShapeSourceOptionMaximumZoomLevelForClustering must be an NSNumber."];
- }
- sourceOptions.zoomRange.min = value.integerValue;
- }
-
- if (NSNumber *value = options[MGLShapeSourceOptionMaximumZoomLevel]) {
- if (![value isKindOfClass:[NSNumber class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"MGLShapeSourceOptionMaximumZoomLevel must be an NSNumber."];
- }
- sourceOptions.zoomRange.max = value.integerValue;
- }
-
- if (NSNumber *value = options[MGLShapeSourceOptionBuffer]) {
- if (![value isKindOfClass:[NSNumber class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"MGLShapeSourceOptionBuffer must be an NSNumber."];
- }
- sourceOptions.tileOptions.buffer = value.integerValue;
- }
-
- if (NSNumber *value = options[MGLShapeSourceOptionSimplificationTolerance]) {
- if (![value isKindOfClass:[NSNumber class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"MGLShapeSourceOptionSimplificationTolerance must be an NSNumber."];
- }
- sourceOptions.tileOptions.tolerance = value.doubleValue;
- }
-
- if (NSNumber *value = options[MGLShapeSourceOptionWrapsCoordinates]) {
- if (![value isKindOfClass:[NSNumber class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"MGLShapeSourceOptionWrapsCoordinates must be an NSNumber."];
- }
- sourceOptions.tileOptions.wrap = value.boolValue;
- }
-
- if (NSNumber *value = options[MGLShapeSourceOptionClipsCoordinates]) {
- if (![value isKindOfClass:[NSNumber class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"MGLShapeSourceOptionClipsCoordinates must be an NSNumber."];
- }
- sourceOptions.tileOptions.clip = value.boolValue;
- }
-
- return sourceOptions;
-}
diff --git a/platform/darwin/src/MGLAccountManager.h b/platform/darwin/src/MGLAccountManager.h
index 741cc323cb..436e45ca9b 100644
--- a/platform/darwin/src/MGLAccountManager.h
+++ b/platform/darwin/src/MGLAccountManager.h
@@ -5,7 +5,7 @@
NS_ASSUME_NONNULL_BEGIN
/**
- The MGLAccountManager object provides a global way to set a Mapbox API access
+ The `MGLAccountManager` object provides a global way to set a Mapbox API access
token.
*/
MGL_EXPORT
@@ -14,9 +14,9 @@ MGL_EXPORT
#pragma mark Authorizing Access
/**
- Set the
+ The
<a href="https://www.mapbox.com/help/define-access-token/">Mapbox access token</a>
- to be used by all instances of MGLMapView in the current application.
+ used by all instances of `MGLMapView` in the current application.
Mapbox-hosted vector tiles and styles require an API access token, which you
can obtain from the
@@ -25,26 +25,18 @@ MGL_EXPORT
your Mapbox account. They also deter other developers from using your styles
without your permission.
- @param accessToken A Mapbox access token. Calling this method with a value of
- `nil` has no effect.
+ Setting this property to a value of `nil` has no effect.
@note You must set the access token before attempting to load any Mapbox-hosted
style. Therefore, you should generally set it before creating an instance of
- MGLMapView. The recommended way to set an access token is to add an entry to
- your application’s Info.plist file with the key `MGLMapboxAccessToken` and
- the type String. Alternatively, you may call this method from your
+ `MGLMapView`. The recommended way to set an access token is to add an entry
+ to your application’s Info.plist file with the key `MGLMapboxAccessToken`
+ and the type `String`. Alternatively, you may call this method from your
application delegate’s `-applicationDidFinishLaunching:` method.
*/
-+ (void)setAccessToken:(nullable NSString *)accessToken;
+@property (class, nullable) NSString *accessToken;
-/**
- Returns the
- <a href="https://www.mapbox.com/help/define-access-token/">Mapbox access token</a>
- in use by instances of MGLMapView in the current application.
- */
-+ (nullable NSString *)accessToken;
-
-+ (BOOL)mapboxMetricsEnabledSettingShownInApp __attribute__((deprecated("Telemetry settings are now always shown in the ℹ️ menu.")));
++ (BOOL)mapboxMetricsEnabledSettingShownInApp __attribute__((unavailable("Telemetry settings are now always shown in the ℹ️ menu.")));
@end
diff --git a/platform/darwin/src/MGLAccountManager.m b/platform/darwin/src/MGLAccountManager.m
index 729caeaa31..73da8ddd63 100644
--- a/platform/darwin/src/MGLAccountManager.m
+++ b/platform/darwin/src/MGLAccountManager.m
@@ -54,11 +54,6 @@
return _sharedManager;
}
-+ (BOOL)mapboxMetricsEnabledSettingShownInApp {
- NSLog(@"mapboxMetricsEnabledSettingShownInApp is no longer necessary; the Mapbox Maps SDK for iOS has changed to always provide a telemetry setting in-app.");
- return YES;
-}
-
+ (void)setAccessToken:(NSString *)accessToken {
accessToken = [accessToken stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
@@ -69,9 +64,7 @@
[MGLAccountManager sharedManager].accessToken = accessToken;
#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
- // Update MGLMapboxEvents
- // NOTE: This is (likely) the initial setup of MGLMapboxEvents
- [MGLMapboxEvents sharedManager];
+ [MGLMapboxEvents setupWithAccessToken:accessToken];
#endif
}
diff --git a/platform/darwin/src/MGLAccountManager_Private.h b/platform/darwin/src/MGLAccountManager_Private.h
index 655af08f20..b68016b1a7 100644
--- a/platform/darwin/src/MGLAccountManager_Private.h
+++ b/platform/darwin/src/MGLAccountManager_Private.h
@@ -3,7 +3,7 @@
@interface MGLAccountManager (Private)
/// Returns the shared instance of the `MGLAccountManager` class.
-+ (instancetype)sharedManager;
+@property (class, nonatomic, readonly) MGLAccountManager *sharedManager;
/// The current global access token.
@property (atomic) NSString *accessToken;
diff --git a/platform/darwin/src/MGLAttributionInfo.mm b/platform/darwin/src/MGLAttributionInfo.mm
index 73147270c1..07d10e852b 100644
--- a/platform/darwin/src/MGLAttributionInfo.mm
+++ b/platform/darwin/src/MGLAttributionInfo.mm
@@ -49,7 +49,12 @@
CGFloat blue;
CGFloat alpha;
#if !TARGET_OS_IPHONE
- linkColor = [linkColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
+ // CSS uses the sRGB color space.
+ if ([NSColor redColor].colorSpaceName == NSCalibratedRGBColorSpace) {
+ linkColor = [linkColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
+ } else {
+ linkColor = [linkColor colorUsingColorSpace:[NSColorSpace sRGBColorSpace]];
+ }
#endif
[linkColor getRed:&red green:&green blue:&blue alpha:&alpha];
[css appendFormat:
diff --git a/platform/darwin/src/MGLBackgroundStyleLayer.h b/platform/darwin/src/MGLBackgroundStyleLayer.h
index 9d2673c859..d5c3ed5403 100644
--- a/platform/darwin/src/MGLBackgroundStyleLayer.h
+++ b/platform/darwin/src/MGLBackgroundStyleLayer.h
@@ -37,6 +37,7 @@ which it is added.
#pragma mark - Accessing the Paint Attributes
+#if TARGET_OS_IPHONE
/**
The color with which the background will be drawn.
@@ -59,6 +60,30 @@ which it is added.
feature attributes.
*/
@property (nonatomic, null_resettable) NSExpression *backgroundColor;
+#else
+/**
+ The color with which the background will be drawn.
+
+ The default value of this property is an expression that evaluates to
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `backgroundPattern` is set to
+ `nil`. Otherwise, it is ignored.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant `NSColor` values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$zoomLevel` variable
+
+ This property does not support applying interpolation or step functions to
+ feature attributes.
+ */
+@property (nonatomic, null_resettable) NSExpression *backgroundColor;
+#endif
/**
The transition affecting any changes to this layer’s `backgroundColor` property.
@@ -71,11 +96,11 @@ which it is added.
The opacity at which the background will be drawn.
The default value of this property is an expression that evaluates to the float
- `1`. Set this property to `nil` to reset it to the default value.
+ 1. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between 0 and 1 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
diff --git a/platform/darwin/src/MGLBackgroundStyleLayer.mm b/platform/darwin/src/MGLBackgroundStyleLayer.mm
index 7c4cf79709..993645d3a8 100644
--- a/platform/darwin/src/MGLBackgroundStyleLayer.mm
+++ b/platform/darwin/src/MGLBackgroundStyleLayer.mm
@@ -116,7 +116,8 @@
if (propertyValue.isUndefined()) {
propertyValue = self.rawLayer->getDefaultBackgroundPattern();
}
- return MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ NSExpression *expression = MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ return expression.mgl_expressionByReplacingTokensWithKeyPaths;
}
- (void)setBackgroundPatternTransition:(MGLTransition )transition {
diff --git a/platform/darwin/src/MGLCircleStyleLayer.h b/platform/darwin/src/MGLCircleStyleLayer.h
index caa6d2f6cb..06b4de32f0 100644
--- a/platform/darwin/src/MGLCircleStyleLayer.h
+++ b/platform/darwin/src/MGLCircleStyleLayer.h
@@ -62,9 +62,10 @@ typedef NS_ENUM(NSUInteger, MGLCircleTranslationAnchor) {
circles on the map.
Use a circle style layer to configure the visual appearance of point or point
- collection features in vector tiles loaded by an `MGLVectorSource` object or
- `MGLPointAnnotation`, `MGLPointFeature`, `MGLPointCollection`, or
- `MGLPointCollectionFeature` instances in an `MGLShapeSource` object.
+ collection features. These features can come from vector tiles loaded by an
+ `MGLVectorTileSource` object, or they can be `MGLPointAnnotation`,
+ `MGLPointFeature`, `MGLPointCollection`, or `MGLPointCollectionFeature`
+ instances in an `MGLShapeSource` or `MGLComputedShapeSource` object.
A circle style layer renders circles whose radii are measured in screen units.
To display circles on the map whose radii correspond to real-world distances,
@@ -83,7 +84,7 @@ typedef NS_ENUM(NSUInteger, MGLCircleTranslationAnchor) {
let layer = MGLCircleStyleLayer(identifier: "circles", source: population)
layer.sourceLayerIdentifier = "population"
layer.circleColor = NSExpression(forConstantValue: UIColor.green)
- layer.circleRadius = NSExpression(format: "FUNCTION($zoomLevel, 'mgl_interpolateWithCurveType:parameters:stops:', 'exponential', 1.75, %@)",
+ layer.circleRadius = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'exponential', 1.75, %@)",
[12: 2,
22: 180])
layer.circleOpacity = NSExpression(forConstantValue: 0.7)
@@ -116,7 +117,7 @@ MGL_EXPORT
full opacity.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
@@ -136,6 +137,7 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition circleBlurTransition;
+#if TARGET_OS_IPHONE
/**
The fill color of the circle.
@@ -153,6 +155,25 @@ MGL_EXPORT
feature attributes
*/
@property (nonatomic, null_resettable) NSExpression *circleColor;
+#else
+/**
+ The fill color of the circle.
+
+ The default value of this property is an expression that evaluates to
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant `NSColor` values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$zoomLevel` variable and/or
+ feature attributes
+ */
+@property (nonatomic, null_resettable) NSExpression *circleColor;
+#endif
/**
The transition affecting any changes to this layer’s `circleColor` property.
@@ -165,11 +186,11 @@ MGL_EXPORT
The opacity at which the circle will be drawn.
The default value of this property is an expression that evaluates to the float
- `1`. Set this property to `nil` to reset it to the default value.
+ 1. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between 0 and 1 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -214,11 +235,11 @@ MGL_EXPORT
This property is measured in points.
The default value of this property is an expression that evaluates to the float
- `5`. Set this property to `nil` to reset it to the default value.
+ 5. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -264,6 +285,7 @@ MGL_EXPORT
@property (nonatomic, null_resettable) NSExpression *circlePitchScale __attribute__((unavailable("Use circleScaleAlignment instead.")));
+#if TARGET_OS_IPHONE
/**
The stroke color of the circle.
@@ -281,6 +303,25 @@ MGL_EXPORT
feature attributes
*/
@property (nonatomic, null_resettable) NSExpression *circleStrokeColor;
+#else
+/**
+ The stroke color of the circle.
+
+ The default value of this property is an expression that evaluates to
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant `NSColor` values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$zoomLevel` variable and/or
+ feature attributes
+ */
+@property (nonatomic, null_resettable) NSExpression *circleStrokeColor;
+#endif
/**
The transition affecting any changes to this layer’s `circleStrokeColor` property.
@@ -293,11 +334,11 @@ MGL_EXPORT
The opacity of the circle's stroke.
The default value of this property is an expression that evaluates to the float
- `1`. Set this property to `nil` to reset it to the default value.
+ 1. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between 0 and 1 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -320,11 +361,11 @@ MGL_EXPORT
This property is measured in points.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
diff --git a/platform/darwin/src/MGLComputedShapeSource.h b/platform/darwin/src/MGLComputedShapeSource.h
index f90f2c94b1..068c49245c 100644
--- a/platform/darwin/src/MGLComputedShapeSource.h
+++ b/platform/darwin/src/MGLComputedShapeSource.h
@@ -1,15 +1,38 @@
-#import "MGLAbstractShapeSource.h"
-
#import "MGLFoundation.h"
#import "MGLGeometry.h"
#import "MGLTypes.h"
-#import "MGLShape.h"
+#import "MGLShapeSource.h"
NS_ASSUME_NONNULL_BEGIN
@protocol MGLFeature;
/**
+ An `NSNumber` object containing a Boolean value; specifies whether the shape of
+ an `MGLComputedShapeSource` should be wrapped to accomodate coordinates with
+ longitudes beyond −180 and 180. The default value is `NO`.
+
+ Setting this option to `YES` affects rendering performance.
+
+ This option is used with the `MGLComputedShapeSource` class; it is ignored when
+ creating an `MGLShapeSource` object.
+ */
+extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionWrapsCoordinates;
+
+/**
+ An `NSNumber` object containing a Boolean value; specifies whether the shape of
+ an `MGLComputedShapeSource` should be clipped at the edge of each tile. The
+ default value is `NO`.
+
+ Setting this option to `YES` affects rendering performance. Use this option to
+ clip `MGLPolyline`s and `MGLPolygon`s at tile boundaries without artifacts.
+
+ This option is used with the `MGLComputedShapeSource` class; it is ignored when
+ creating an `MGLShapeSource` object.
+ */
+extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClipsCoordinates;
+
+/**
Data source for `MGLComputedShapeSource`. This protocol defines two optional methods for fetching
data, one based on tile coordinates, and one based on a bounding box. Classes that implement this
protocol must implement one, and only one of the methods. Methods on this protocol will not be
@@ -38,21 +61,42 @@ NS_ASSUME_NONNULL_BEGIN
@end
/**
- A source for vector data that is fetched one tile at a time. Useful for sources that are
- too large to fit in memory, or are already divided into tiles, but not in Mapbox Vector Tile format.
+ `MGLComputedShapeSource` is a map content source that supplies vector shapes,
+ one tile at a time, to be shown on the map on demand. You implement a class
+ conforming to the `MGLComputedShapeSourceDataSource` protocol that returns
+ instances of `MGLShape` or `MGLFeature`, then add a computed shape source to an
+ `MGLStyle` object along with an `MGLVectorStyleLayer` object. The vector style
+ layer defines the appearance of any content supplied by the computed shape
+ source.
- Supported options are `MGLShapeSourceOptionMinimumZoomLevel`, `MGLShapeSourceOptionMaximumZoomLevel`,
- `MGLShapeSourceOptionBuffer`, and `MGLShapeSourceOptionSimplificationTolerance.` This source does
- not support clustering.
+ `MGLComputedShapeSource` is similar to `MGLShapeSource` but is optimized for
+ data sets that change dynamically or are too large to fit completely in memory.
+ It is also useful for data that is divided into tiles in a format other than
+ <a href="https://www.mapbox.com/vector-tiles/">Mapbox Vector Tiles</a>. For
+ <a href="http://geojson.org/">GeoJSON</a> data, use the `MGLShapeSource` class.
+ For static tiles or Mapbox Vector Tiles, use the `MGLVectorTileSource` class.
+
+ You can add and remove sources dynamically using methods such as
+ `-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`. This class
+ cannot be represented in a style JSON file; you must add it ot the style at
+ runtime.
*/
MGL_EXPORT
-@interface MGLComputedShapeSource : MGLAbstractShapeSource
+@interface MGLComputedShapeSource : MGLSource
/**
Returns a custom shape data source initialized with an identifier, and a
dictionary of options for the source according to the
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson">style
specification</a>.
+
+ This class supports the following options:
+ `MGLShapeSourceOptionMinimumZoomLevel`, `MGLShapeSourceOptionMaximumZoomLevel`,
+ `MGLShapeSourceOptionBuffer`,
+ `MGLShapeSourceOptionSimplificationTolerance`,
+ `MGLShapeSourceOptionWrapsCoordinates`, and
+ `MGLShapeSourceOptionClipsCoordinates`. Shapes provided by a computed
+ shape source cannot be clustered.
@param identifier A string that uniquely identifies the source.
@param options An `NSDictionary` of options for this source.
@@ -64,6 +108,14 @@ MGL_EXPORT
dictionary of options for the source according to the
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson">style
specification</a>.
+
+ This class supports the following options:
+ `MGLShapeSourceOptionMinimumZoomLevel`, `MGLShapeSourceOptionMaximumZoomLevel`,
+ `MGLShapeSourceOptionBuffer`,
+ `MGLShapeSourceOptionSimplificationTolerance`,
+ `MGLShapeSourceOptionWrapsCoordinates`, and
+ `MGLShapeSourceOptionClipsCoordinates`. Shapes provided by a computed shape
+ source cannot be clustered.
@param identifier A string that uniquely identifies the source.
@param options An `NSDictionary` of options for this source.
diff --git a/platform/darwin/src/MGLComputedShapeSource.mm b/platform/darwin/src/MGLComputedShapeSource.mm
index 0a3c92bb97..fb25eb8eb4 100644
--- a/platform/darwin/src/MGLComputedShapeSource.mm
+++ b/platform/darwin/src/MGLComputedShapeSource.mm
@@ -1,9 +1,8 @@
-#import "MGLComputedShapeSource.h"
+#import "MGLComputedShapeSource_Private.h"
#import "MGLMapView_Private.h"
#import "MGLSource_Private.h"
#import "MGLShape_Private.h"
-#import "MGLAbstractShapeSource_Private.h"
#import "MGLGeometry_Private.h"
#include <mbgl/map/map.hpp>
@@ -11,6 +10,63 @@
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/util/geojson.hpp>
+const MGLShapeSourceOption MGLShapeSourceOptionWrapsCoordinates = @"MGLShapeSourceOptionWrapsCoordinates";
+const MGLShapeSourceOption MGLShapeSourceOptionClipsCoordinates = @"MGLShapeSourceOptionClipsCoordinates";
+
+mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options) {
+ mbgl::style::CustomGeometrySource::Options sourceOptions;
+
+ if (NSNumber *value = options[MGLShapeSourceOptionMinimumZoomLevel]) {
+ if (![value isKindOfClass:[NSNumber class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"MGLShapeSourceOptionMaximumZoomLevelForClustering must be an NSNumber."];
+ }
+ sourceOptions.zoomRange.min = value.integerValue;
+ }
+
+ if (NSNumber *value = options[MGLShapeSourceOptionMaximumZoomLevel]) {
+ if (![value isKindOfClass:[NSNumber class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"MGLShapeSourceOptionMaximumZoomLevel must be an NSNumber."];
+ }
+ sourceOptions.zoomRange.max = value.integerValue;
+ }
+
+ if (NSNumber *value = options[MGLShapeSourceOptionBuffer]) {
+ if (![value isKindOfClass:[NSNumber class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"MGLShapeSourceOptionBuffer must be an NSNumber."];
+ }
+ sourceOptions.tileOptions.buffer = value.integerValue;
+ }
+
+ if (NSNumber *value = options[MGLShapeSourceOptionSimplificationTolerance]) {
+ if (![value isKindOfClass:[NSNumber class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"MGLShapeSourceOptionSimplificationTolerance must be an NSNumber."];
+ }
+ sourceOptions.tileOptions.tolerance = value.doubleValue;
+ }
+
+ if (NSNumber *value = options[MGLShapeSourceOptionWrapsCoordinates]) {
+ if (![value isKindOfClass:[NSNumber class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"MGLShapeSourceOptionWrapsCoordinates must be an NSNumber."];
+ }
+ sourceOptions.tileOptions.wrap = value.boolValue;
+ }
+
+ if (NSNumber *value = options[MGLShapeSourceOptionClipsCoordinates]) {
+ if (![value isKindOfClass:[NSNumber class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"MGLShapeSourceOptionClipsCoordinates must be an NSNumber."];
+ }
+ sourceOptions.tileOptions.clip = value.boolValue;
+ }
+
+ return sourceOptions;
+}
+
@interface MGLComputedShapeSource () {
std::unique_ptr<mbgl::style::CustomGeometrySource> _pendingSource;
}
diff --git a/platform/darwin/src/MGLAbstractShapeSource_Private.h b/platform/darwin/src/MGLComputedShapeSource_Private.h
index ddde55b149..e1887caf8d 100644
--- a/platform/darwin/src/MGLAbstractShapeSource_Private.h
+++ b/platform/darwin/src/MGLComputedShapeSource_Private.h
@@ -1,22 +1,12 @@
-#import "MGLAbstractShapeSource.h"
-
#import "MGLFoundation.h"
#import "MGLTypes.h"
-#import "MGLShape.h"
+#import "MGLComputedShapeSource.h"
-#include <mbgl/style/sources/geojson_source.hpp>
#include <mbgl/style/sources/custom_geometry_source.hpp>
NS_ASSUME_NONNULL_BEGIN
-@interface MGLAbstractShapeSource (Private)
-
-MGL_EXPORT
-
-mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options);
-
MGL_EXPORT
mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options);
-@end
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLFeature.h b/platform/darwin/src/MGLFeature.h
index a13821cf96..d0c9e26062 100644
--- a/platform/darwin/src/MGLFeature.h
+++ b/platform/darwin/src/MGLFeature.h
@@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
The `MGLFeature` protocol is used to provide details about geographic features
- contained in an `MGLShapeSource` or `MGLVectorSource` object. Each concrete
+ contained in an `MGLShapeSource` or `MGLVectorTileSource` object. Each concrete
subclass of `MGLShape` in turn has a subclass that conforms to this protocol. A
feature object associates a shape with an optional identifier and attributes.
@@ -23,8 +23,8 @@ NS_ASSUME_NONNULL_BEGIN
In addition to adding data to the map, you can also extract data from the map:
`-[MGLMapView visibleFeaturesAtPoint:]` and related methods return feature
objects that correspond to features in the source. This enables you to inspect
- the properties of features in vector tiles loaded by `MGLVectorSource` objects.
- You also reuse these feature objects as overlay annotations.
+ the properties of features in vector tiles loaded by `MGLVectorTileSource`
+ objects. You also reuse these feature objects as overlay annotations.
While it is possible to add `MGLFeature`-conforming objects to the map as
annotations using `-[MGLMapView addAnnotations:]` and related methods, doing so
@@ -43,12 +43,12 @@ NS_ASSUME_NONNULL_BEGIN
source.
You can configure an `MGLVectorStyleLayer` object to include or exclude a
- specific feature in an `MGLShapeSource` or `MGLVectorSource`. In the
+ specific feature in an `MGLShapeSource` or `MGLVectorTileSource`. In the
`MGLVectorStyleLayer.predicate` property, compare the special `$id` attribute
to the feature’s identifier.
- In vector tiles loaded by `MGLVectorSource` objects, the identifier corresponds
- to the
+ In vector tiles loaded by `MGLVectorTileSource` objects, the identifier
+ corresponds to the
<a href="https://github.com/mapbox/vector-tile-spec/tree/master/2.1#42-features">feature identifier</a>
(`id`). If the source does not specify the feature’s identifier, the value of
this property is `nil`. If specified, the identifier may be an integer,
@@ -83,7 +83,7 @@ NS_ASSUME_NONNULL_BEGIN
A dictionary of attributes for this feature.
You can configure an `MGLVectorStyleLayer` object to include or exclude a
- specific feature in an `MGLShapeSource` or `MGLVectorSource`. In the
+ specific feature in an `MGLShapeSource` or `MGLVectorTileSource`. In the
`MGLVectorStyleLayer.predicate` property, compare a key of the attribute
dictionary to the value you want to include. For example, if you want an
`MGLLineStyleLayer` object to display only important features, you might assign
@@ -107,7 +107,7 @@ NS_ASSUME_NONNULL_BEGIN
`MGLSymbolStyleLayer.textField` to an `MGLStyleValue` object containing the
raw string value `{name}`.
- In vector tiles loaded by `MGLVectorSource` objects, the keys and values of
+ In vector tiles loaded by `MGLVectorTileSource` objects, the keys and values of
each feature’s attribute dictionary are determined by the source. Each
attribute name is a string, while each attribute value may be a null value,
Boolean value, integer, floating-point number, or string. These data types are
@@ -238,11 +238,12 @@ MGL_EXPORT
An `MGLShapeCollectionFeature` object associates a shape collection with an
optional identifier and attributes.
- `MGLShapeCollectionFeature` is most commonly used to add multiple shapes to a single
- `MGLShapeSource`. Configure the appearance of an `MGLSource`’s shape collection
- collectively using an `MGLSymbolStyleLayer` object, or use multiple instances of
- `MGLCircleStyleLayer`, `MGLFillStyleLayer`, and `MGLLineStyleLayer` to
- configure the appearance of each kind of shape inside the collection.
+ `MGLShapeCollectionFeature` is most commonly used to add multiple shapes to a
+ single `MGLShapeSource`. Configure the appearance of an `MGLSource`’s shape
+ collection collectively using an `MGLSymbolStyleLayer` object, or use multiple
+ instances of `MGLCircleStyleLayer`, `MGLFillStyleLayer`, and
+ `MGLLineStyleLayer` to configure the appearance of each kind of shape inside
+ the collection.
A shape collection feature is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.3">feature collection</a>
diff --git a/platform/darwin/src/MGLFillExtrusionStyleLayer.h b/platform/darwin/src/MGLFillExtrusionStyleLayer.h
index d1d5af6ba2..7c3a0773e4 100644
--- a/platform/darwin/src/MGLFillExtrusionStyleLayer.h
+++ b/platform/darwin/src/MGLFillExtrusionStyleLayer.h
@@ -29,9 +29,10 @@ typedef NS_ENUM(NSUInteger, MGLFillExtrusionTranslationAnchor) {
extruded polygons on the map.
Use a fill-extrusion style layer to configure the visual appearance of polygon
- or multipolygon features in vector tiles loaded by an `MGLVectorSource` object
- or `MGLPolygon`, `MGLPolygonFeature`, `MGLMultiPolygon`, or
- `MGLMultiPolygonFeature` instances in an `MGLShapeSource` object.
+ or multipolygon features. These features can come from vector tiles loaded by
+ an `MGLVectorTileSource` object, or they can be `MGLPolygon`,
+ `MGLPolygonFeature`, `MGLMultiPolygon`, or `MGLMultiPolygonFeature` instances
+ in an `MGLShapeSource` or `MGLComputedShapeSource` object.
You can access an existing fill-extrusion style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
@@ -77,14 +78,14 @@ MGL_EXPORT
This property is measured in meters.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `fillExtrusionHeight` is
non-`nil`. Otherwise, it is ignored.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -100,6 +101,7 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition fillExtrusionBaseTransition;
+#if TARGET_OS_IPHONE
/**
The base color of this layer. The extrusion's surfaces will be shaded
differently based on this color in combination with the `light` settings. If
@@ -123,6 +125,31 @@ MGL_EXPORT
feature attributes
*/
@property (nonatomic, null_resettable) NSExpression *fillExtrusionColor;
+#else
+/**
+ The base color of this layer. The extrusion's surfaces will be shaded
+ differently based on this color in combination with the `light` settings. If
+ this color is specified with an alpha component, the alpha component will be
+ ignored; use `fillExtrusionOpacity` to set layer opacityco.
+
+ The default value of this property is an expression that evaluates to
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `fillExtrusionPattern` is set to
+ `nil`. Otherwise, it is ignored.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant `NSColor` values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$zoomLevel` variable and/or
+ feature attributes
+ */
+@property (nonatomic, null_resettable) NSExpression *fillExtrusionColor;
+#endif
/**
The transition affecting any changes to this layer’s `fillExtrusionColor` property.
@@ -137,11 +164,11 @@ MGL_EXPORT
This property is measured in meters.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -162,11 +189,11 @@ MGL_EXPORT
per-layer, not per-feature, basis, and data-driven styling is not available.
The default value of this property is an expression that evaluates to the float
- `1`. Set this property to `nil` to reset it to the default value.
+ 1. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between 0 and 1 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
diff --git a/platform/darwin/src/MGLFillExtrusionStyleLayer.mm b/platform/darwin/src/MGLFillExtrusionStyleLayer.mm
index 1baa264689..688ce4c1ac 100644
--- a/platform/darwin/src/MGLFillExtrusionStyleLayer.mm
+++ b/platform/darwin/src/MGLFillExtrusionStyleLayer.mm
@@ -231,7 +231,8 @@ namespace mbgl {
if (propertyValue.isUndefined()) {
propertyValue = self.rawLayer->getDefaultFillExtrusionPattern();
}
- return MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ NSExpression *expression = MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ return expression.mgl_expressionByReplacingTokensWithKeyPaths;
}
- (void)setFillExtrusionPatternTransition:(MGLTransition )transition {
diff --git a/platform/darwin/src/MGLFillStyleLayer.h b/platform/darwin/src/MGLFillStyleLayer.h
index 5caab91b45..a159a924e6 100644
--- a/platform/darwin/src/MGLFillStyleLayer.h
+++ b/platform/darwin/src/MGLFillStyleLayer.h
@@ -28,9 +28,10 @@ typedef NS_ENUM(NSUInteger, MGLFillTranslationAnchor) {
optionally stroked) polygons on the map.
Use a fill style layer to configure the visual appearance of polygon or
- multipolygon features in vector tiles loaded by an `MGLVectorSource` object or
- `MGLPolygon`, `MGLPolygonFeature`, `MGLMultiPolygon`, or
- `MGLMultiPolygonFeature` instances in an `MGLShapeSource` object.
+ multipolygon features. These features can come from vector tiles loaded by an
+ `MGLVectorTileSource` object, or they can be `MGLPolygon`, `MGLPolygonFeature`,
+ `MGLMultiPolygon`, or `MGLMultiPolygonFeature` instances in an `MGLShapeSource`
+ or `MGLComputedShapeSource` object.
You can access an existing fill style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
@@ -94,6 +95,7 @@ MGL_EXPORT
@property (nonatomic, null_resettable) NSExpression *fillAntialias __attribute__((unavailable("Use fillAntialiased instead.")));
+#if TARGET_OS_IPHONE
/**
The color of the filled part of this layer.
@@ -114,6 +116,28 @@ MGL_EXPORT
feature attributes
*/
@property (nonatomic, null_resettable) NSExpression *fillColor;
+#else
+/**
+ The color of the filled part of this layer.
+
+ The default value of this property is an expression that evaluates to
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `fillPattern` is set to `nil`.
+ Otherwise, it is ignored.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant `NSColor` values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$zoomLevel` variable and/or
+ feature attributes
+ */
+@property (nonatomic, null_resettable) NSExpression *fillColor;
+#endif
/**
The transition affecting any changes to this layer’s `fillColor` property.
@@ -127,11 +151,11 @@ MGL_EXPORT
value will also affect the 1pt stroke around the fill, if the stroke is used.
The default value of this property is an expression that evaluates to the float
- `1`. Set this property to `nil` to reset it to the default value.
+ 1. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between 0 and 1 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -147,6 +171,7 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition fillOpacityTransition;
+#if TARGET_OS_IPHONE
/**
The outline color of the fill. Matches the value of `fillColor` if unspecified.
@@ -164,6 +189,25 @@ MGL_EXPORT
feature attributes
*/
@property (nonatomic, null_resettable) NSExpression *fillOutlineColor;
+#else
+/**
+ The outline color of the fill. Matches the value of `fillColor` if unspecified.
+
+ This property is only applied to the style if `fillPattern` is set to `nil`,
+ and `fillAntialiased` is set to an expression that evaluates to `YES`.
+ Otherwise, it is ignored.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant `NSColor` values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$zoomLevel` variable and/or
+ feature attributes
+ */
+@property (nonatomic, null_resettable) NSExpression *fillOutlineColor;
+#endif
/**
The transition affecting any changes to this layer’s `fillOutlineColor` property.
diff --git a/platform/darwin/src/MGLFillStyleLayer.mm b/platform/darwin/src/MGLFillStyleLayer.mm
index ab28b414b5..c975e28d6b 100644
--- a/platform/darwin/src/MGLFillStyleLayer.mm
+++ b/platform/darwin/src/MGLFillStyleLayer.mm
@@ -220,7 +220,8 @@ namespace mbgl {
if (propertyValue.isUndefined()) {
propertyValue = self.rawLayer->getDefaultFillPattern();
}
- return MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ NSExpression *expression = MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ return expression.mgl_expressionByReplacingTokensWithKeyPaths;
}
- (void)setFillPatternTransition:(MGLTransition )transition {
diff --git a/platform/darwin/src/MGLGeometry.h b/platform/darwin/src/MGLGeometry.h
index 7c68033abf..a8d3759106 100644
--- a/platform/darwin/src/MGLGeometry.h
+++ b/platform/darwin/src/MGLGeometry.h
@@ -14,6 +14,24 @@ typedef struct __attribute__((objc_boxable)) MGLCoordinateSpan {
CLLocationDegrees longitudeDelta;
} MGLCoordinateSpan;
+/* Defines a point on the map in Mercator projection for a specific zoom level. */
+typedef struct __attribute__((objc_boxable)) MGLMapPoint {
+ /** X coordinate representing a longitude in Mercator projection. */
+ CGFloat x;
+ /** Y coordinate representing a latitide in Mercator projection. */
+ CGFloat y;
+ /** Zoom level at which the X and Y coordinates are valid. */
+ CGFloat zoomLevel;
+} MGLMapPoint;
+
+/* Defines a 4x4 matrix. */
+typedef struct MGLMatrix4 {
+ double m00, m01, m02, m03;
+ double m10, m11, m12, m13;
+ double m20, m21, m22, m23;
+ double m30, m31, m32, m33;
+} MGLMatrix4;
+
/**
Creates a new `MGLCoordinateSpan` from the given latitudinal and longitudinal
deltas.
@@ -26,6 +44,17 @@ NS_INLINE MGLCoordinateSpan MGLCoordinateSpanMake(CLLocationDegrees latitudeDelt
}
/**
+ Creates a new `MGLMapPoint` from the given X and Y coordinates, and zoom level.
+ */
+NS_INLINE MGLMapPoint MGLMapPointMake(CGFloat x, CGFloat y, CGFloat zoomLevel) {
+ MGLMapPoint point;
+ point.x = x;
+ point.y = y;
+ point.zoomLevel = zoomLevel;
+ return point;
+}
+
+/**
Returns `YES` if the two coordinate spans represent the same latitudinal change
and the same longitudinal change.
*/
@@ -181,4 +210,7 @@ NS_INLINE CLLocationDegrees MGLDegreesFromRadians(CGFloat radians) {
return radians * 180 / M_PI;
}
+/** Returns Mercator projection of a WGS84 coordinate at the specified zoom level. */
+extern MGL_EXPORT MGLMapPoint MGLMapPointForCoordinate(CLLocationCoordinate2D coordinate, double zoomLevel);
+
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLGeometry.mm b/platform/darwin/src/MGLGeometry.mm
index 715a70f0b8..6785779570 100644
--- a/platform/darwin/src/MGLGeometry.mm
+++ b/platform/darwin/src/MGLGeometry.mm
@@ -106,3 +106,19 @@ CGPoint MGLPointRounded(CGPoint point) {
#endif
return CGPointMake(round(point.x * scaleFactor) / scaleFactor, round(point.y * scaleFactor) / scaleFactor);
}
+
+MGLMapPoint MGLMapPointForCoordinate(CLLocationCoordinate2D coordinate, double zoomLevel) {
+ mbgl::Point<double> projectedCoordinate = mbgl::Projection::project(MGLLatLngFromLocationCoordinate2D(coordinate), std::pow(2.0, zoomLevel));
+ return MGLMapPointMake(projectedCoordinate.x, projectedCoordinate.y, zoomLevel);
+}
+
+MGLMatrix4 MGLMatrix4Make(std::array<double, 16> array) {
+ MGLMatrix4 mat4 = {
+ .m00 = array[0], .m01 = array[1], .m02 = array[2], .m03 = array[3],
+ .m10 = array[4], .m11 = array[5], .m12 = array[6], .m13 = array[7],
+ .m20 = array[8], .m21 = array[9], .m22 = array[10], .m23 = array[11],
+ .m30 = array[12], .m31 = array[13], .m32 = array[14], .m33 = array[15]
+ };
+ return mat4;
+}
+
diff --git a/platform/darwin/src/MGLGeometry_Private.h b/platform/darwin/src/MGLGeometry_Private.h
index 8b9c6c2327..0bff9b09f5 100644
--- a/platform/darwin/src/MGLGeometry_Private.h
+++ b/platform/darwin/src/MGLGeometry_Private.h
@@ -128,3 +128,5 @@ MGLRadianCoordinate2D MGLRadianCoordinateAtDistanceFacingDirection(MGLRadianCoor
CLLocationDirection MGLDirectionBetweenCoordinates(CLLocationCoordinate2D firstCoordinate, CLLocationCoordinate2D secondCoordinate);
CGPoint MGLPointRounded(CGPoint point);
+
+MGLMatrix4 MGLMatrix4Make(std::array<double, 16> mat);
diff --git a/platform/darwin/src/MGLHeatmapStyleLayer.h b/platform/darwin/src/MGLHeatmapStyleLayer.h
index 35095fd52e..ad7ba5de01 100644
--- a/platform/darwin/src/MGLHeatmapStyleLayer.h
+++ b/platform/darwin/src/MGLHeatmapStyleLayer.h
@@ -13,10 +13,11 @@ NS_ASSUME_NONNULL_BEGIN
A heatmap visualizes the spatial distribution of a large, dense set of point
data, using color to avoid cluttering the map with individual points at low
zoom levels. The points are weighted by an attribute you specify. Use a heatmap
- style layer in conjunction with point or point collection features in vector
- tiles loaded by an `MGLVectorSource` object or `MGLPointAnnotation`,
- `MGLPointFeature`, `MGLPointCollection`, or `MGLPointCollectionFeature`
- instances in an `MGLShapeSource` object.
+ style layer in conjunction with point or point collection features. These
+ features can come from vector tiles loaded by an `MGLVectorTileSource` object,
+ or they can be `MGLPointAnnotation`, `MGLPointFeature`, `MGLPointCollection`,
+ or `MGLPointCollectionFeature` instances in an `MGLShapeSource` or
+ `MGLComputedShapeSource` object.
Consider accompanying a heatmap style layer with an `MGLCircleStyleLayer` or
`MGLSymbolStyleLayer` at high zoom levels. If you are unsure whether the point
@@ -35,10 +36,10 @@ NS_ASSUME_NONNULL_BEGIN
```swift
let layer = MGLHeatmapStyleLayer(identifier: "earthquake-heat", source: earthquakes)
- layer.heatmapWeight = NSExpression(format: "FUNCTION(magnitude, 'mgl_interpolateWithCurveType:parameters:stops:', 'linear', nil, %@)",
+ layer.heatmapWeight = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:(magnitude, 'linear', nil, %@)",
[0: 0,
6: 1])
- layer.heatmapIntensity = NSExpression(format: "FUNCTION($zoomLevel, 'mgl_interpolateWithCurveType:parameters:stops:', 'linear', nil, %@)",
+ layer.heatmapIntensity = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)",
[0: 1,
9: 3])
mapView.style?.addLayer(layer)
@@ -64,9 +65,11 @@ MGL_EXPORT
#pragma mark - Accessing the Paint Attributes
+#if TARGET_OS_IPHONE
/**
- Defines the color of each point based on its density value in a heatmap. Should
- be an expression that uses `$heatmapDensity` as input.
+ The color of each screen point based on its density value in a heatmap. This
+ property is normally set to an interpolation or step expression with the
+ `$heatmapDensity` value as its input.
The default value of this property is an expression that evaluates to a rainbow
color scale from blue to red. Set this property to `nil` to reset it to the
@@ -84,17 +87,40 @@ MGL_EXPORT
feature attributes.
*/
@property (nonatomic, null_resettable) NSExpression *heatmapColor;
+#else
+/**
+ The color of each screen point based on its density value in a heatmap. This
+ property is normally set to an interpolation or step expression with the
+ `$heatmapDensity` value as its input.
+
+ The default value of this property is an expression that evaluates to a rainbow
+ color scale from blue to red. Set this property to `nil` to reset it to the
+ default value.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant `NSColor` values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$heatmapDensity` variable
+
+ This property does not support applying interpolation or step functions to
+ feature attributes.
+ */
+@property (nonatomic, null_resettable) NSExpression *heatmapColor;
+#endif
/**
Similar to `heatmapWeight` but controls the intensity of the heatmap globally.
Primarily used for adjusting the heatmap based on zoom level.
The default value of this property is an expression that evaluates to the float
- `1`. Set this property to `nil` to reset it to the default value.
+ 1. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -116,11 +142,11 @@ MGL_EXPORT
The global opacity at which the heatmap layer will be drawn.
The default value of this property is an expression that evaluates to the float
- `1`. Set this property to `nil` to reset it to the default value.
+ 1. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between 0 and 1 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -145,11 +171,11 @@ MGL_EXPORT
This property is measured in points.
The default value of this property is an expression that evaluates to the float
- `30`. Set this property to `nil` to reset it to the default value.
+ 30. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 1
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -171,11 +197,11 @@ MGL_EXPORT
Especially useful when combined with clustering.
The default value of this property is an expression that evaluates to the float
- `1`. Set this property to `nil` to reset it to the default value.
+ 1. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
diff --git a/platform/darwin/src/MGLHillshadeStyleLayer.h b/platform/darwin/src/MGLHillshadeStyleLayer.h
index b2eeb59aba..224680160a 100644
--- a/platform/darwin/src/MGLHillshadeStyleLayer.h
+++ b/platform/darwin/src/MGLHillshadeStyleLayer.h
@@ -36,7 +36,7 @@ typedef NS_ENUM(NSUInteger, MGLHillshadeIlluminationAnchor) {
To display posterized hillshading based on vector shapes, as with the <a
href="https://www.mapbox.com/vector-tiles/mapbox-terrain/">Mapbox Terrain</a>
- source, use an `MGLVectorSource` object in conjunction with several
+ source, use an `MGLVectorTileSource` object in conjunction with several
`MGLFillStyleLayer` objects.
You can access an existing hillshade style layer using the
@@ -75,6 +75,7 @@ MGL_EXPORT
#pragma mark - Accessing the Paint Attributes
+#if TARGET_OS_IPHONE
/**
The shading color used to accentuate rugged terrain like sharp cliffs and
gorges.
@@ -95,6 +96,28 @@ MGL_EXPORT
feature attributes.
*/
@property (nonatomic, null_resettable) NSExpression *hillshadeAccentColor;
+#else
+/**
+ The shading color used to accentuate rugged terrain like sharp cliffs and
+ gorges.
+
+ The default value of this property is an expression that evaluates to
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant `NSColor` values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$zoomLevel` variable
+
+ This property does not support applying interpolation or step functions to
+ feature attributes.
+ */
+@property (nonatomic, null_resettable) NSExpression *hillshadeAccentColor;
+#endif
/**
The transition affecting any changes to this layer’s `hillshadeAccentColor` property.
@@ -107,11 +130,11 @@ MGL_EXPORT
Intensity of the hillshade
The default value of this property is an expression that evaluates to the float
- `0.5`. Set this property to `nil` to reset it to the default value.
+ 0.5. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between 0 and 1 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -129,6 +152,7 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition hillshadeExaggerationTransition;
+#if TARGET_OS_IPHONE
/**
The shading color of areas that faces towards the light source.
@@ -148,6 +172,27 @@ MGL_EXPORT
feature attributes.
*/
@property (nonatomic, null_resettable) NSExpression *hillshadeHighlightColor;
+#else
+/**
+ The shading color of areas that faces towards the light source.
+
+ The default value of this property is an expression that evaluates to
+ `NSColor.whiteColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant `NSColor` values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$zoomLevel` variable
+
+ This property does not support applying interpolation or step functions to
+ feature attributes.
+ */
+@property (nonatomic, null_resettable) NSExpression *hillshadeHighlightColor;
+#endif
/**
The transition affecting any changes to this layer’s `hillshadeHighlightColor` property.
@@ -187,11 +232,11 @@ MGL_EXPORT
`hillshadeIlluminationAnchor` is set to `MGLHillshadeIlluminationAnchorMap`.
The default value of this property is an expression that evaluates to the float
- `335`. Set this property to `nil` to reset it to the default value.
+ 335. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between 0 and 359 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -202,6 +247,7 @@ MGL_EXPORT
*/
@property (nonatomic, null_resettable) NSExpression *hillshadeIlluminationDirection;
+#if TARGET_OS_IPHONE
/**
The shading color of areas that face away from the light source.
@@ -221,6 +267,27 @@ MGL_EXPORT
feature attributes.
*/
@property (nonatomic, null_resettable) NSExpression *hillshadeShadowColor;
+#else
+/**
+ The shading color of areas that face away from the light source.
+
+ The default value of this property is an expression that evaluates to
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant `NSColor` values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$zoomLevel` variable
+
+ This property does not support applying interpolation or step functions to
+ feature attributes.
+ */
+@property (nonatomic, null_resettable) NSExpression *hillshadeShadowColor;
+#endif
/**
The transition affecting any changes to this layer’s `hillshadeShadowColor` property.
diff --git a/platform/darwin/src/MGLLight.h b/platform/darwin/src/MGLLight.h
index d7e64cbfad..cf4aa50112 100644
--- a/platform/darwin/src/MGLLight.h
+++ b/platform/darwin/src/MGLLight.h
@@ -128,6 +128,7 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition positionTransition;
+#if TARGET_OS_IPHONE
/**
Color tint for lighting extruded geometries.
@@ -150,6 +151,30 @@ MGL_EXPORT
light property in the Mapbox Style Specification.
*/
@property (nonatomic) NSExpression *color;
+#else
+/**
+ Color tint for lighting extruded geometries.
+
+ The default value of this property is an expression that evaluates to
+ `NSColor.whiteColor`.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant `NSColor` values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$zoomLevel` variable
+
+ This property does not support applying interpolation or step functions to
+ feature attributes.
+
+ This property corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-js/style-spec/#light-color"><code>color</code></a>
+ light property in the Mapbox Style Specification.
+ */
+@property (nonatomic) NSExpression *color;
+#endif
/**
The transition affecting any changes to this layer’s `color` property.
@@ -163,11 +188,11 @@ MGL_EXPORT
more extreme contrast.
The default value of this property is an expression that evaluates to the float
- `0.5`.
+ 0.5.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between 0 and 1 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
diff --git a/platform/darwin/src/MGLLineStyleLayer.h b/platform/darwin/src/MGLLineStyleLayer.h
index 003f48ae43..a7510142fc 100644
--- a/platform/darwin/src/MGLLineStyleLayer.h
+++ b/platform/darwin/src/MGLLineStyleLayer.h
@@ -78,9 +78,10 @@ typedef NS_ENUM(NSUInteger, MGLLineTranslationAnchor) {
polylines on the map.
Use a line style layer to configure the visual appearance of polyline or
- multipolyline features in vector tiles loaded by an `MGLVectorSource` object or
- `MGLPolyline`, `MGLPolylineFeature`, `MGLMultiPolyline`, or
- `MGLMultiPolylineFeature` instances in an `MGLShapeSource` object.
+ multipolyline features. These features can come from vector tiles loaded by an
+ `MGLVectorTileSource` object, or they can be `MGLPolyline`,
+ `MGLPolylineFeature`, `MGLMultiPolyline`, or `MGLMultiPolylineFeature`
+ instances in an `MGLShapeSource` or `MGLComputedShapeSource` object.
You can access an existing line style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
@@ -93,7 +94,7 @@ typedef NS_ENUM(NSUInteger, MGLLineTranslationAnchor) {
```swift
let layer = MGLLineStyleLayer(identifier: "trails-path", source: trails)
layer.sourceLayerIdentifier = "trails"
- layer.lineWidth = NSExpression(format: "FUNCTION($zoomLevel, 'mgl_interpolateWithCurveType:parameters:stops:', 'exponential', 1.5, %@)",
+ layer.lineWidth = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'exponential', 1.5, %@)",
[14: 2,
18: 20])
layer.lineColor = NSExpression(forConstantValue: UIColor.brown)
@@ -179,7 +180,7 @@ MGL_EXPORT
Used to automatically convert miter joins to bevel joins for sharp angles.
The default value of this property is an expression that evaluates to the float
- `2`. Set this property to `nil` to reset it to the default value.
+ 2. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `lineJoin` is set to an
expression that evaluates to `miter`. Otherwise, it is ignored.
@@ -201,7 +202,7 @@ MGL_EXPORT
Used to automatically convert round joins to miter joins for shallow angles.
The default value of this property is an expression that evaluates to the float
- `1.05`. Set this property to `nil` to reset it to the default value.
+ 1.05. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `lineJoin` is set to an
expression that evaluates to `round`. Otherwise, it is ignored.
@@ -227,11 +228,11 @@ MGL_EXPORT
This property is measured in points.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -247,6 +248,7 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition lineBlurTransition;
+#if TARGET_OS_IPHONE
/**
The color with which the line will be drawn.
@@ -267,6 +269,28 @@ MGL_EXPORT
feature attributes
*/
@property (nonatomic, null_resettable) NSExpression *lineColor;
+#else
+/**
+ The color with which the line will be drawn.
+
+ The default value of this property is an expression that evaluates to
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `linePattern` is set to `nil`.
+ Otherwise, it is ignored.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant `NSColor` values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$zoomLevel` variable and/or
+ feature attributes
+ */
+@property (nonatomic, null_resettable) NSExpression *lineColor;
+#endif
/**
The transition affecting any changes to this layer’s `lineColor` property.
@@ -291,7 +315,7 @@ MGL_EXPORT
You can set this property to an expression containing any of the following:
- * Constant array values
+ * Constant array values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -319,11 +343,11 @@ MGL_EXPORT
This property is measured in points.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -348,7 +372,7 @@ MGL_EXPORT
This property is measured in points.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
@@ -372,11 +396,11 @@ MGL_EXPORT
The opacity at which the line will be drawn.
The default value of this property is an expression that evaluates to the float
- `1`. Set this property to `nil` to reset it to the default value.
+ 1. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between 0 and 1 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -518,11 +542,11 @@ MGL_EXPORT
This property is measured in points.
The default value of this property is an expression that evaluates to the float
- `1`. Set this property to `nil` to reset it to the default value.
+ 1. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
diff --git a/platform/darwin/src/MGLLineStyleLayer.mm b/platform/darwin/src/MGLLineStyleLayer.mm
index 4e6ff27b39..619cc70afe 100644
--- a/platform/darwin/src/MGLLineStyleLayer.mm
+++ b/platform/darwin/src/MGLLineStyleLayer.mm
@@ -390,7 +390,8 @@ namespace mbgl {
if (propertyValue.isUndefined()) {
propertyValue = self.rawLayer->getDefaultLinePattern();
}
- return MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ NSExpression *expression = MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ return expression.mgl_expressionByReplacingTokensWithKeyPaths;
}
- (void)setLinePatternTransition:(MGLTransition )transition {
diff --git a/platform/darwin/src/MGLMapSnapshotter.h b/platform/darwin/src/MGLMapSnapshotter.h
index 426ab1bb00..976213c8ba 100644
--- a/platform/darwin/src/MGLMapSnapshotter.h
+++ b/platform/darwin/src/MGLMapSnapshotter.h
@@ -140,7 +140,7 @@ typedef void (^MGLMapSnapshotCompletionHandler)(MGLMapSnapshot* _Nullable snapsh
```swift
let camera = MGLMapCamera(lookingAtCenter: CLLocationCoordinate2D(latitude: 37.7184, longitude: -122.4365), fromDistance: 100, pitch: 20, heading: 0)
- let options = MGLMapSnapshotOptions(styleURL: MGLStyle.satelliteStreetsStyleURL(), camera: camera, size: CGSize(width: 320, height: 480))
+ let options = MGLMapSnapshotOptions(styleURL: MGLStyle.satelliteStreetsStyleURL, camera: camera, size: CGSize(width: 320, height: 480))
options.zoomLevel = 10
let snapshotter = MGLMapSnapshotter(options: options)
diff --git a/platform/darwin/src/MGLNetworkConfiguration.h b/platform/darwin/src/MGLNetworkConfiguration.h
index 644291ee13..2db46d78c5 100644
--- a/platform/darwin/src/MGLNetworkConfiguration.h
+++ b/platform/darwin/src/MGLNetworkConfiguration.h
@@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface MGLNetworkConfiguration : NSObject
/// Returns the shared instance of the `MGLNetworkConfiguration` class.
-+ (instancetype)sharedManager;
+@property (class, nonatomic, readonly) MGLNetworkConfiguration *sharedManager;
/// The current API base URL. If `nil`, the Mapbox default base API URL is in use.
@property (atomic, nullable) NSURL *apiBaseURL;
diff --git a/platform/darwin/src/MGLOfflineStorage.h b/platform/darwin/src/MGLOfflineStorage.h
index b009f893b3..a1f3e686c2 100644
--- a/platform/darwin/src/MGLOfflineStorage.h
+++ b/platform/darwin/src/MGLOfflineStorage.h
@@ -70,7 +70,7 @@ typedef NSString *MGLOfflinePackUserInfoKey NS_EXTENSIBLE_STRING_ENUM;
*/
extern MGL_EXPORT const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyState;
-extern MGL_EXPORT NSString * const MGLOfflinePackStateUserInfoKey __attribute__((deprecated("Use MGLOfflinePackUserInfoKeyState")));
+extern MGL_EXPORT NSString * const MGLOfflinePackStateUserInfoKey __attribute__((unavailable("Use MGLOfflinePackUserInfoKeyState")));
/**
The key for an `NSValue` object that indicates an offline pack’s current
@@ -81,7 +81,7 @@ extern MGL_EXPORT NSString * const MGLOfflinePackStateUserInfoKey __attribute__(
*/
extern MGL_EXPORT const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyProgress;
-extern MGL_EXPORT NSString * const MGLOfflinePackProgressUserInfoKey __attribute__((deprecated("Use MGLOfflinePackUserInfoKeyProgress")));
+extern MGL_EXPORT NSString * const MGLOfflinePackProgressUserInfoKey __attribute__((unavailable("Use MGLOfflinePackUserInfoKeyProgress")));
/**
The key for an `NSError` object that is encountered in the course of
@@ -91,7 +91,7 @@ extern MGL_EXPORT NSString * const MGLOfflinePackProgressUserInfoKey __attribute
*/
extern MGL_EXPORT const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyError;
-extern MGL_EXPORT NSString * const MGLOfflinePackErrorUserInfoKey __attribute__((deprecated("Use MGLOfflinePackUserInfoKeyError")));
+extern MGL_EXPORT NSString * const MGLOfflinePackErrorUserInfoKey __attribute__((unavailable("Use MGLOfflinePackUserInfoKeyError")));
/**
The key for an `NSNumber` object that indicates the maximum number of
@@ -103,7 +103,7 @@ extern MGL_EXPORT NSString * const MGLOfflinePackErrorUserInfoKey __attribute__(
*/
extern MGL_EXPORT const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyMaximumCount;
-extern MGL_EXPORT NSString * const MGLOfflinePackMaximumCountUserInfoKey __attribute__((deprecated("Use MGLOfflinePackUserInfoKeyMaximumCount")));
+extern MGL_EXPORT NSString * const MGLOfflinePackMaximumCountUserInfoKey __attribute__((unavailable("Use MGLOfflinePackUserInfoKeyMaximumCount")));
/**
A block to be called once an offline pack has been completely created and
@@ -170,7 +170,7 @@ MGL_EXPORT
/**
Returns the shared offline storage object.
*/
-+ (instancetype)sharedOfflineStorage;
+@property (class, nonatomic, readonly) MGLOfflineStorage *sharedOfflineStorage;
#pragma mark - Accessing the Delegate
diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm
index 7085aa58e5..4d999144e8 100644
--- a/platform/darwin/src/MGLOfflineStorage.mm
+++ b/platform/darwin/src/MGLOfflineStorage.mm
@@ -26,13 +26,9 @@ const NSNotificationName MGLOfflinePackErrorNotification = @"MGLOfflinePackError
const NSNotificationName MGLOfflinePackMaximumMapboxTilesReachedNotification = @"MGLOfflinePackMaximumMapboxTilesReached";
const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyState = @"State";
-NSString * const MGLOfflinePackStateUserInfoKey = MGLOfflinePackUserInfoKeyState;
const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyProgress = @"Progress";
-NSString * const MGLOfflinePackProgressUserInfoKey = MGLOfflinePackUserInfoKeyProgress;
const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyError = @"Error";
-NSString * const MGLOfflinePackErrorUserInfoKey = MGLOfflinePackUserInfoKeyError;
const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyMaximumCount = @"MaximumCount";
-NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoKeyMaximumCount;
@interface MGLOfflineStorage ()
diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.h b/platform/darwin/src/MGLOpenGLStyleLayer.h
index 0b494e8062..df8d2c5365 100644
--- a/platform/darwin/src/MGLOpenGLStyleLayer.h
+++ b/platform/darwin/src/MGLOpenGLStyleLayer.h
@@ -1,9 +1,11 @@
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
+#import <QuartzCore/QuartzCore.h>
#import "MGLFoundation.h"
#import "MGLStyleValue.h"
#import "MGLStyleLayer.h"
+#import "MGLGeometry.h"
NS_ASSUME_NONNULL_BEGIN
@@ -17,6 +19,7 @@ typedef struct MGLStyleLayerDrawingContext {
CLLocationDirection direction;
CGFloat pitch;
CGFloat fieldOfView;
+ MGLMatrix4 projectionMatrix;
} MGLStyleLayerDrawingContext;
MGL_EXPORT
diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.mm b/platform/darwin/src/MGLOpenGLStyleLayer.mm
index 8933a77382..d89fbc80c3 100644
--- a/platform/darwin/src/MGLOpenGLStyleLayer.mm
+++ b/platform/darwin/src/MGLOpenGLStyleLayer.mm
@@ -3,53 +3,53 @@
#import "MGLMapView_Private.h"
#import "MGLStyle_Private.h"
#import "MGLStyleLayer_Private.h"
+#import "MGLGeometry_Private.h"
#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/math/wrap.hpp>
-/**
- Runs the preparation handler block contained in the given context, which is
- implicitly an instance of `MGLOpenGLStyleLayer`.
+class MGLOpenGLLayerHost : public mbgl::style::CustomLayerHost {
+public:
+ MGLOpenGLLayerHost(MGLOpenGLStyleLayer *styleLayer) {
+ layerRef = styleLayer;
+ layer = nil;
+ }
- @param context An `MGLOpenGLStyleLayer` instance that was provided as context
- when creating an OpenGL style layer.
- */
-void MGLPrepareCustomStyleLayer(void *context) {
- MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context;
- [layer didMoveToMapView:layer.style.mapView];
-}
+ void initialize() {
+ if (layerRef == nil) return;
+ else if (layer == nil) layer = layerRef;
-/**
- Runs the drawing handler block contained in the given context, which is
- implicitly an instance of `MGLOpenGLStyleLayer`.
+ [layer didMoveToMapView:layer.style.mapView];
+ }
- @param context An `MGLOpenGLStyleLayer` instance that was provided as context
- when creating an OpenGL style layer.
- */
-void MGLDrawCustomStyleLayer(void *context, const mbgl::style::CustomLayerRenderParameters &params) {
- MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context;
- MGLStyleLayerDrawingContext drawingContext = {
- .size = CGSizeMake(params.width, params.height),
- .centerCoordinate = CLLocationCoordinate2DMake(params.latitude, params.longitude),
- .zoomLevel = params.zoom,
- .direction = mbgl::util::wrap(params.bearing, 0., 360.),
- .pitch = static_cast<CGFloat>(params.pitch),
- .fieldOfView = static_cast<CGFloat>(params.fieldOfView),
- };
- [layer drawInMapView:layer.style.mapView withContext:drawingContext];
-}
+ void render(const mbgl::style::CustomLayerRenderParameters &params) {
+ if(!layer) return;
+
+ MGLStyleLayerDrawingContext drawingContext = {
+ .size = CGSizeMake(params.width, params.height),
+ .centerCoordinate = CLLocationCoordinate2DMake(params.latitude, params.longitude),
+ .zoomLevel = params.zoom,
+ .direction = mbgl::util::wrap(params.bearing, 0., 360.),
+ .pitch = static_cast<CGFloat>(params.pitch),
+ .fieldOfView = static_cast<CGFloat>(params.fieldOfView),
+ .projectionMatrix = MGLMatrix4Make(params.projectionMatrix)
+ };
+ [layer drawInMapView:layer.style.mapView withContext:drawingContext];
+ }
-/**
- Runs the completion handler block contained in the given context, which is
- implicitly an instance of `MGLOpenGLStyleLayer`.
+ void contextLost() {}
- @param context An `MGLOpenGLStyleLayer` instance that was provided as context
- when creating an OpenGL style layer.
- */
-void MGLFinishCustomStyleLayer(void *context) {
- MGLOpenGLStyleLayer *layer = (__bridge_transfer MGLOpenGLStyleLayer *)context;
- [layer willMoveFromMapView:layer.style.mapView];
-}
+ void deinitialize() {
+ if (layer == nil) return;
+
+ [layer willMoveFromMapView:layer.style.mapView];
+ layerRef = layer;
+ layer = nil;
+ }
+private:
+ __weak MGLOpenGLStyleLayer * layerRef;
+ MGLOpenGLStyleLayer * layer = nil;
+};
/**
An `MGLOpenGLStyleLayer` is a style layer that is rendered by OpenGL code that
@@ -98,10 +98,7 @@ void MGLFinishCustomStyleLayer(void *context) {
*/
- (instancetype)initWithIdentifier:(NSString *)identifier {
auto layer = std::make_unique<mbgl::style::CustomLayer>(identifier.UTF8String,
- MGLPrepareCustomStyleLayer,
- MGLDrawCustomStyleLayer,
- MGLFinishCustomStyleLayer,
- (__bridge_retained void *)self);
+ std::make_unique<MGLOpenGLLayerHost>(self));
return self = [super initWithPendingLayer:std::move(layer)];
}
@@ -110,22 +107,15 @@ void MGLFinishCustomStyleLayer(void *context) {
}
#pragma mark - Adding to and removing from a map view
-
-- (void)setStyle:(MGLStyle *)style {
- if (_style && style) {
- [NSException raise:@"MGLLayerReuseException"
- format:@"%@ cannot be added to more than one MGLStyle at a time.", self];
- }
- _style = style;
-}
-
- (void)addToStyle:(MGLStyle *)style belowLayer:(MGLStyleLayer *)otherLayer {
self.style = style;
+ self.style.openGLLayers[self.identifier] = self;
[super addToStyle:style belowLayer:otherLayer];
}
- (void)removeFromStyle:(MGLStyle *)style {
[super removeFromStyle:style];
+ self.style.openGLLayers[self.identifier] = nil;
self.style = nil;
}
diff --git a/platform/darwin/src/MGLPointAnnotation.h b/platform/darwin/src/MGLPointAnnotation.h
index 1ef0962f99..3dac7a969c 100644
--- a/platform/darwin/src/MGLPointAnnotation.h
+++ b/platform/darwin/src/MGLPointAnnotation.h
@@ -15,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN
You can add point shapes to the map by adding them to an `MGLShapeSource`
object. Configure the appearance of an `MGLShapeSource`’s or
- `MGLVectorSource`’s point shapes collectively using an `MGLCircleStyleLayer` or
+ `MGLVectorTileSource`’s point shapes collectively using an `MGLCircleStyleLayer` or
`MGLSymbolStyleLayer` object.
For more interactivity, add a selectable point annotation to a map view using
@@ -28,7 +28,8 @@ NS_ASSUME_NONNULL_BEGIN
default content of the annotation’s callout (on iOS) or popover (on macOS).
To group multiple related points together in one shape, use an
- `MGLPointCollection` or `MGLShapeCollection` object.
+ `MGLPointCollection` or `MGLShapeCollection` object. To access
+ a point’s attributes, use an `MGLPointFeature` object.
A point shape is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.2">Point</a> geometry
diff --git a/platform/darwin/src/MGLPointCollection.h b/platform/darwin/src/MGLPointCollection.h
index 74b30385a0..65ce95cb0f 100644
--- a/platform/darwin/src/MGLPointCollection.h
+++ b/platform/darwin/src/MGLPointCollection.h
@@ -14,8 +14,9 @@
You can add point collections to the map by adding them to an `MGLShapeSource`
object. Configure the appearance of an `MGLShapeSource`’s or
- `MGLVectorSource`’s point collections collectively using an
- `MGLCircleStyleLayer` or `MGLSymbolStyleLayer` object.
+ `MGLVectorTileSource`’s point collections collectively using an
+ `MGLCircleStyleLayer` or `MGLSymbolStyleLayer` object. To access a point
+ collection’s attributes, use an `MGLPointCollectionFeature` object.
You cannot add an `MGLPointCollection` object directly to a map view as an
annotation. However, you can create individual `MGLPointAnnotation` objects
diff --git a/platform/darwin/src/MGLPolygon.h b/platform/darwin/src/MGLPolygon.h
index 3fcc1be76d..190b6df9c5 100644
--- a/platform/darwin/src/MGLPolygon.h
+++ b/platform/darwin/src/MGLPolygon.h
@@ -17,8 +17,9 @@ NS_ASSUME_NONNULL_BEGIN
You can add polygon shapes to the map by adding them to an `MGLShapeSource`
object. Configure the appearance of an `MGLShapeSource`’s or
- `MGLVectorSource`’s polygons collectively using an `MGLFillStyleLayer` or
- `MGLSymbolStyleLayer` object.
+ `MGLVectorTileSource`’s polygons collectively using an `MGLFillStyleLayer` or
+ `MGLSymbolStyleLayer` object. To access a polygon’s attributes, use an
+ `MGLPolygonFeature` object.
Alternatively, you can add a polygon overlay directly to a map view using the
`-[MGLMapView addAnnotation:]` or `-[MGLMapView addOverlay:]` method. Configure
@@ -95,8 +96,8 @@ MGL_EXPORT
You can add multipolygon shapes to the map by adding them to an
`MGLShapeSource` object. Configure the appearance of an `MGLShapeSource`’s or
- `MGLVectorSource`’s multipolygons collectively using an `MGLFillStyleLayer` or
- `MGLSymbolStyleLayer` object.
+ `MGLVectorTileSource`’s multipolygons collectively using an `MGLFillStyleLayer`
+ or `MGLSymbolStyleLayer` object.
You cannot add an `MGLMultiPolygon` object directly to a map view using
`-[MGLMapView addAnnotation:]` or `-[MGLMapView addOverlay:]`. However, you can
diff --git a/platform/darwin/src/MGLPolyline.h b/platform/darwin/src/MGLPolyline.h
index e46baa91cc..b1fca5bf28 100644
--- a/platform/darwin/src/MGLPolyline.h
+++ b/platform/darwin/src/MGLPolyline.h
@@ -17,8 +17,9 @@ NS_ASSUME_NONNULL_BEGIN
You can add polyline shapes to the map by adding them to an `MGLShapeSource`
object. Configure the appearance of an `MGLShapeSource`’s or
- `MGLVectorSource`’s polylines collectively using an `MGLLineStyleLayer` or
- `MGLSymbolStyleLayer` object.
+ `MGLVectorTileSource`’s polylines collectively using an `MGLLineStyleLayer` or
+ `MGLSymbolStyleLayer` object. To access a polyline’s attributes, use an
+ `MGLPolylineFeature` object.
Alternatively, you can add a polyline overlay directly to a map view using the
`-[MGLMapView addAnnotation:]` or `-[MGLMapView addOverlay:]` method. Configure
@@ -74,8 +75,8 @@ MGL_EXPORT
You can add multipolyline shapes to the map by adding them to an
`MGLShapeSource` object. Configure the appearance of an `MGLShapeSource`’s or
- `MGLVectorSource`’s multipolylines collectively using an `MGLLineStyleLayer` or
- `MGLSymbolStyleLayer` object.
+ `MGLVectorTileSource`’s multipolylines collectively using an
+ `MGLLineStyleLayer` or `MGLSymbolStyleLayer` object.
You cannot add an `MGLMultiPolyline` object directly to a map view using
`-[MGLMapView addAnnotation:]` or `-[MGLMapView addOverlay:]`. However, you can
diff --git a/platform/darwin/src/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm
index e011d09215..26e3518cd8 100644
--- a/platform/darwin/src/MGLPolyline.mm
+++ b/platform/darwin/src/MGLPolyline.mm
@@ -72,9 +72,12 @@
if (count > 1 || middle > traveled) {
for (NSUInteger i = 0; i < count; i++) {
-
+
+ // Avoid a heap buffer overflow when there are only two coordinates.
+ NSUInteger nextIndex = (i + 1 == count) ? 0 : 1;
+
MGLRadianCoordinate2D from = MGLRadianCoordinateFromLocationCoordinate(coordinates[i]);
- MGLRadianCoordinate2D to = MGLRadianCoordinateFromLocationCoordinate(coordinates[i + 1]);
+ MGLRadianCoordinate2D to = MGLRadianCoordinateFromLocationCoordinate(coordinates[i + nextIndex]);
if (traveled >= middle) {
double overshoot = middle - traveled;
@@ -91,7 +94,6 @@
}
traveled += (MGLDistanceBetweenRadianCoordinates(from, to) * mbgl::util::EARTH_RADIUS_M);
-
}
}
diff --git a/platform/darwin/src/MGLRasterDEMSource.h b/platform/darwin/src/MGLRasterDEMSource.h
index d00912ca79..d439fe1645 100644
--- a/platform/darwin/src/MGLRasterDEMSource.h
+++ b/platform/darwin/src/MGLRasterDEMSource.h
@@ -1,6 +1,19 @@
#import "MGLFoundation.h"
-#import "MGLRasterSource.h"
+#import "MGLRasterTileSource.h"
+
+/**
+ An `NSNumber` object containing an unsigned integer that specifies the encoding
+ formula for raster-dem tilesets. The integer corresponds to one of
+ the constants described in `MGLDEMEncoding`.
+
+ The default value for this option is `MGLDEMEncodingMapbox`.
+
+ This option cannot be represented in a TileJSON or style JSON file. It is used
+ with the `MGLRasterDEMSource` class and is ignored when creating an
+ `MGLRasterTileSource` or `MGLVectorTileSource` object.
+ */
+extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionDEMEncoding;
/**
`MGLRasterDEMSource` is a map content source that supplies rasterized
@@ -32,6 +45,6 @@
```
*/
MGL_EXPORT
-@interface MGLRasterDEMSource : MGLRasterSource
+@interface MGLRasterDEMSource : MGLRasterTileSource
@end
diff --git a/platform/darwin/src/MGLRasterDEMSource.mm b/platform/darwin/src/MGLRasterDEMSource.mm
index d8639b70e3..27614b9ef4 100644
--- a/platform/darwin/src/MGLRasterDEMSource.mm
+++ b/platform/darwin/src/MGLRasterDEMSource.mm
@@ -1,6 +1,6 @@
#import "MGLRasterDEMSource.h"
-#import "MGLRasterSource_Private.h"
+#import "MGLRasterTileSource_Private.h"
#import "NSURL+MGLAdditions.h"
#import <mbgl/style/sources/raster_dem_source.hpp>
diff --git a/platform/darwin/src/MGLRasterStyleLayer.h b/platform/darwin/src/MGLRasterStyleLayer.h
index 7773246cad..bca9649e5d 100644
--- a/platform/darwin/src/MGLRasterStyleLayer.h
+++ b/platform/darwin/src/MGLRasterStyleLayer.h
@@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
imagery on the map, especially raster tiles.
Use a raster style layer to configure the color parameters of raster tiles
- loaded by an `MGLRasterSource` object or raster images loaded by an
+ loaded by an `MGLRasterTileSource` object or raster images loaded by an
`MGLImageSource` object. For example, you could use a raster style layer to
render <a href="https://www.mapbox.com/satellite/">Mapbox Satellite</a>
imagery, a <a
@@ -64,7 +64,7 @@ MGL_EXPORT
brightness.
The default value of this property is an expression that evaluates to the float
- `1`. Set this property to `nil` to reset it to the default value.
+ 1. Set this property to `nil` to reset it to the default value.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-brightness-max"><code>raster-brightness-max</code></a>
@@ -72,7 +72,7 @@ MGL_EXPORT
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between 0 and 1 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -97,7 +97,7 @@ MGL_EXPORT
brightness.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. Set this property to `nil` to reset it to the default value.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-brightness-min"><code>raster-brightness-min</code></a>
@@ -105,7 +105,7 @@ MGL_EXPORT
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between 0 and 1 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -129,11 +129,11 @@ MGL_EXPORT
Increase or reduce the contrast of the image.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between −1 and 1 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -157,11 +157,11 @@ MGL_EXPORT
This property is measured in milliseconds.
The default value of this property is an expression that evaluates to the float
- `300`. Set this property to `nil` to reset it to the default value.
+ 300. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -178,7 +178,7 @@ MGL_EXPORT
This property is measured in degrees.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. Set this property to `nil` to reset it to the default value.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-hue-rotate"><code>raster-hue-rotate</code></a>
@@ -210,11 +210,11 @@ MGL_EXPORT
The opacity at which the image will be drawn.
The default value of this property is an expression that evaluates to the float
- `1`. Set this property to `nil` to reset it to the default value.
+ 1. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between 0 and 1 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -236,11 +236,11 @@ MGL_EXPORT
Increase or reduce the saturation of the image.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. Set this property to `nil` to reset it to the default value.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between −1 and 1 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
diff --git a/platform/darwin/src/MGLRasterSource.h b/platform/darwin/src/MGLRasterTileSource.h
index 4f4b7c96c3..59b256d5e5 100644
--- a/platform/darwin/src/MGLRasterSource.h
+++ b/platform/darwin/src/MGLRasterTileSource.h
@@ -8,56 +8,59 @@ NS_ASSUME_NONNULL_BEGIN
/**
An `NSNumber` object containing a floating-point number that specifies the
width and height (measured in points) at which the map displays each raster
- image tile when the map’s zoom level is an integer. The raster source scales
- its images up or down when the map’s zoom level falls between two integers.
+ image tile when the map’s zoom level is an integer. The raster tile source
+ scales its images up or down when the map’s zoom level falls between two
+ integers.
The default value for this option is 512. Version 4 of the
<a href="https://www.mapbox.com/api-documentation/#maps">Mapbox Maps API</a>
requires a value of 256, as do many third-party tile servers, so consult your
provider’s documentation for the correct value.
- This option is only applicable to `MGLRasterSource` objects; it is ignored when
- initializing `MGLVectorSource` objects.
+ This option is only applicable to `MGLRasterTileSource` objects; it is ignored
+ when initializing `MGLVectorTileSource` objects.
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionTileSize;
/**
- `MGLRasterSource` is a map content source that supplies raster image tiles to
- be shown on the map. The location of and metadata about the tiles are defined
- either by an option dictionary or by an external file that conforms to the
+ `MGLRasterTileSource` is a map content source that supplies raster image tiles
+ to be shown on the map. The location of and metadata about the tiles are
+ defined either by an option dictionary or by an external file that conforms to
+ the
<a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>.
- A raster source is added to an `MGLStyle` object along with one or more
+ A raster tile 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 raster source.
+ appearance of content supplied by the raster tile source.
Each
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-raster"><code>raster</code></a>
source defined by the style JSON file is represented at runtime by an
- `MGLRasterSource` object that you can use to initialize new style layers. You
+ `MGLRasterTileSource` 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 source = MGLRasterSource(identifier: "clouds", tileURLTemplates: ["https://example.com/raster-tiles/{z}/{x}/{y}.png"], options: [
+ let source = MGLRasterTileSource(identifier: "clouds", tileURLTemplates: ["https://example.com/raster-tiles/{z}/{x}/{y}.png"], options: [
.minimumZoomLevel: 9,
.maximumZoomLevel: 16,
.tileSize: 512,
.attributionInfos: [
- MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
+ MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "https://mapbox.com"))
]
])
mapView.style?.addSource(source)
```
*/
MGL_EXPORT
-@interface MGLRasterSource : MGLTileSource
+@interface MGLRasterTileSource : MGLTileSource
#pragma mark Initializing a Source
/**
- Returns a raster source initialized with an identifier and configuration URL.
+ Returns a raster tile source initialized with an identifier and configuration
+ URL.
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
@@ -77,13 +80,13 @@ MGL_EXPORT
which it is added.
@param configurationURL A URL to a TileJSON configuration file describing the
source’s contents and other metadata.
- @return An initialized raster source.
+ @return An initialized raster tile source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL;
/**
- Returns a raster source initialized with an identifier, configuration URL, and
- tile size.
+ Returns a raster tile source initialized with an identifier, configuration URL,
+ and tile size.
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
@@ -98,14 +101,14 @@ MGL_EXPORT
@param configurationURL A URL to a TileJSON configuration file describing the
source’s contents and other metadata.
@param tileSize The width and height (measured in points) of each tiled image
- in the raster source. See the `MGLTileSourceOptionTileSize` documentation
- for details.
- @return An initialized raster source.
+ in the raster tile source. See the `MGLTileSourceOptionTileSize`
+ documentation for details.
+ @return An initialized raster tile source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize NS_DESIGNATED_INITIALIZER;
/**
- Returns a raster source initialized an identifier, tile URL templates, and
+ Returns a raster tile source initialized an identifier, tile URL templates, and
options.
Tile URL templates are strings that specify the URLs of the raster tile images
diff --git a/platform/darwin/src/MGLRasterSource.mm b/platform/darwin/src/MGLRasterTileSource.mm
index c47cc199eb..02cfef4ae8 100644
--- a/platform/darwin/src/MGLRasterSource.mm
+++ b/platform/darwin/src/MGLRasterTileSource.mm
@@ -1,4 +1,4 @@
-#import "MGLRasterSource_Private.h"
+#import "MGLRasterTileSource_Private.h"
#import "MGLMapView_Private.h"
#import "MGLSource_Private.h"
@@ -10,16 +10,16 @@
const MGLTileSourceOption MGLTileSourceOptionTileSize = @"MGLTileSourceOptionTileSize";
-static const CGFloat MGLRasterSourceClassicTileSize = 256;
-static const CGFloat MGLRasterSourceRetinaTileSize = 512;
+static const CGFloat MGLRasterTileSourceClassicTileSize = 256;
+static const CGFloat MGLRasterTileSourceRetinaTileSize = 512;
-@interface MGLRasterSource ()
+@interface MGLRasterTileSource ()
@property (nonatomic, readonly) mbgl::style::RasterSource *rawSource;
@end
-@implementation MGLRasterSource
+@implementation MGLRasterTileSource
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL {
// The style specification default is 512, but 256 is the expected value for
@@ -28,7 +28,7 @@ static const CGFloat MGLRasterSourceRetinaTileSize = 512;
BOOL isMapboxURL = ([configurationURL.scheme isEqualToString:@"mapbox"]
&& [configurationURL.host containsString:@"."]
&& (!configurationURL.path.length || [configurationURL.path isEqualToString:@"/"]));
- CGFloat tileSize = isMapboxURL ? MGLRasterSourceClassicTileSize : MGLRasterSourceRetinaTileSize;
+ CGFloat tileSize = isMapboxURL ? MGLRasterTileSourceClassicTileSize : MGLRasterTileSourceRetinaTileSize;
return [self initWithIdentifier:identifier configurationURL:configurationURL tileSize:tileSize];
}
@@ -47,7 +47,7 @@ static const CGFloat MGLRasterSourceRetinaTileSize = 512;
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options {
mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
- uint16_t tileSize = MGLRasterSourceRetinaTileSize;
+ uint16_t tileSize = MGLRasterTileSourceRetinaTileSize;
if (NSNumber *tileSizeNumber = options[MGLTileSourceOptionTileSize]) {
if (![tileSizeNumber isKindOfClass:[NSNumber class]]) {
[NSException raise:NSInvalidArgumentException
diff --git a/platform/darwin/src/MGLRasterSource_Private.h b/platform/darwin/src/MGLRasterTileSource_Private.h
index 6f40fbc5a9..128dcb447d 100644
--- a/platform/darwin/src/MGLRasterSource_Private.h
+++ b/platform/darwin/src/MGLRasterTileSource_Private.h
@@ -1,4 +1,4 @@
-#import "MGLRasterSource.h"
+#import "MGLRasterTileSource.h"
#include <memory>
@@ -10,7 +10,7 @@ namespace mbgl {
NS_ASSUME_NONNULL_BEGIN
-@interface MGLRasterSource (Private)
+@interface MGLRasterTileSource (Private)
@property (nonatomic, readonly) mbgl::style::RasterSource *rawSource;
diff --git a/platform/darwin/src/MGLRendererConfiguration.h b/platform/darwin/src/MGLRendererConfiguration.h
index 31aad0a742..34c8e9628b 100644
--- a/platform/darwin/src/MGLRendererConfiguration.h
+++ b/platform/darwin/src/MGLRendererConfiguration.h
@@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface MGLRendererConfiguration : NSObject
/** Returns an instance of the current renderer configuration. */
-+ (instancetype)currentConfiguration;
+@property (class, nonatomic, readonly) MGLRendererConfiguration *currentConfiguration;
/** The file source to use. Defaults to `mbgl::DefaultFileSource` */
@property (nonatomic, readonly) mbgl::DefaultFileSource *fileSource;
diff --git a/platform/darwin/src/MGLShape.h b/platform/darwin/src/MGLShape.h
index e965710552..e0ef0999db 100644
--- a/platform/darwin/src/MGLShape.h
+++ b/platform/darwin/src/MGLShape.h
@@ -12,21 +12,23 @@ NS_ASSUME_NONNULL_BEGIN
Create instances of `MGLPointAnnotation`, `MGLPointCollection`, `MGLPolyline`,
`MGLMultiPolyline`, `MGLPolygon`, `MGLMultiPolygon`, or `MGLShapeCollection` in
- order to use `MGLShape`'s methods. Do not create instances of `MGLShape` directly,
- and do not create your own subclasses of this class. The shape classes correspond
- to the <a href="https://tools.ietf.org/html/rfc7946#section-3.1">Geometry</a> object
+ order to use `MGLShape`'s methods. Do not create instances of `MGLShape`
+ directly, and do not create your own subclasses of this class. The shape
+ classes correspond to the
+ <a href="https://tools.ietf.org/html/rfc7946#section-3.1">Geometry</a> object
types in the GeoJSON standard, but some have nonstandard names for backwards
compatibility.
Although you do not create instances of this class directly, you can use its
`+[MGLShape shapeWithData:encoding:error:]` factory method to create one of the
- concrete subclasses of `MGLShape` noted above from GeoJSON data.
+ concrete subclasses of `MGLShape` noted above from GeoJSON data. To access a
+ shape’s attributes, use the corresponding `MGLFeature` class instead.
You can add shapes to the map by adding them to an `MGLShapeSource` object.
- Configure the appearance of an `MGLShapeSource`’s or `MGLVectorSource`’s shapes
- collectively using a concrete instance of `MGLVectorStyleLayer`. Alternatively,
- you can add some kinds of shapes directly to a map view as annotations or
- overlays.
+ Configure the appearance of an `MGLShapeSource`’s or `MGLVectorTileSource`’s
+ shapes collectively using a concrete instance of `MGLVectorStyleLayer`.
+ Alternatively, you can add some kinds of shapes directly to a map view as
+ annotations or overlays.
*/
MGL_EXPORT
@interface MGLShape : NSObject <MGLAnnotation, NSSecureCoding>
diff --git a/platform/darwin/src/MGLShapeCollection.h b/platform/darwin/src/MGLShapeCollection.h
index bb107ee7f0..bec482ca61 100644
--- a/platform/darwin/src/MGLShapeCollection.h
+++ b/platform/darwin/src/MGLShapeCollection.h
@@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
`MGLShapeCollection` is most commonly used to add multiple shapes to a single
`MGLShapeSource`. Configure the appearance of an `MGLShapeSource`’s or
- `MGLVectorSource`’s shape collection collectively using an
+ `MGLVectorTileSource`’s shape collection collectively using an
`MGLSymbolStyleLayer` object, or use multiple instances of
`MGLCircleStyleLayer`, `MGLFillStyleLayer`, and `MGLLineStyleLayer` to
configure the appearance of each kind of shape inside the collection.
@@ -27,7 +27,8 @@ NS_ASSUME_NONNULL_BEGIN
To represent a collection of point, polyline, or polygon shapes, it may be more
convenient to use an `MGLPointCollection`, `MGLMultiPolyline`, or
- `MGLMultiPolygon` object, respectively.
+ `MGLMultiPolygon` object, respectively. To access a shape collection’s
+ attributes, use the corresponding `MGLFeature` object.
A shape collection is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.8">GeometryCollection</a>
diff --git a/platform/darwin/src/MGLShapeSource.h b/platform/darwin/src/MGLShapeSource.h
index 929609e91f..6fa93476be 100644
--- a/platform/darwin/src/MGLShapeSource.h
+++ b/platform/darwin/src/MGLShapeSource.h
@@ -1,12 +1,99 @@
-#import "MGLAbstractShapeSource.h"
-
#import "MGLFoundation.h"
#import "MGLTypes.h"
-#import "MGLShape.h"
+#import "MGLSource.h"
NS_ASSUME_NONNULL_BEGIN
@protocol MGLFeature;
+@class MGLShape;
+
+/**
+ Options for `MGLShapeSource` objects.
+ */
+typedef NSString *MGLShapeSourceOption NS_STRING_ENUM;
+
+/**
+ An `NSNumber` object containing a Boolean enabling or disabling clustering.
+ If the `shape` property contains point shapes, setting this option to
+ `YES` clusters the points by radius into groups. The default value is `NO`.
+
+ This option corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-cluster"><code>cluster</code></a>
+ source property in the Mapbox Style Specification.
+
+ This option only affects point features within an `MGLShapeSource` object; it
+ is ignored when creating an `MGLComputedShapeSource` object.
+ */
+extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClustered;
+
+/**
+ An `NSNumber` object containing an integer; specifies the radius of each
+ cluster if clustering is enabled. A value of 512 produces a radius equal to
+ the width of a tile. The default value is 50.
+
+ This option only affects point features within an `MGLShapeSource` object; it
+ is ignored when creating an `MGLComputedShapeSource` object.
+ */
+extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius;
+
+/**
+ An `NSNumber` object containing an integer; specifies the maximum zoom level at
+ which to cluster points if clustering is enabled. Defaults to one zoom level
+ less than the value of `MGLShapeSourceOptionMaximumZoomLevel` so that, at the
+ maximum zoom level, the shapes are not clustered.
+
+ This option corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-clusterMaxZoom"><code>clusterMaxZoom</code></a>
+ source property in the Mapbox Style Specification.
+
+ This option only affects point features within an `MGLShapeSource` object; it
+ is ignored when creating an `MGLComputedShapeSource` object.
+ */
+extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering;
+
+/**
+ An `NSNumber` object containing an integer; specifies the minimum zoom level at
+ which to create vector tiles. The default value is 0.
+
+ This option corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-minzoom"><code>minzoom</code></a>
+ source property in the Mapbox Style Specification.
+ */
+extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMinimumZoomLevel;
+
+/**
+ An `NSNumber` object containing an integer; specifies the maximum zoom level at
+ which to create vector tiles. A greater value produces greater detail at high
+ zoom levels. The default value is 18.
+
+ This option corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-maxzoom"><code>maxzoom</code></a>
+ source property in the Mapbox Style Specification.
+ */
+extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel;
+
+/**
+ An `NSNumber` object containing an integer; specifies the size of the tile
+ buffer on each side. A value of 0 produces no buffer. A value of 512 produces a
+ buffer as wide as the tile itself. Larger values produce fewer rendering
+ artifacts near tile edges and slower performance. The default value is 128.
+
+ This option corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-buffer"><code>buffer</code></a>
+ source property in the Mapbox Style Specification.
+ */
+extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionBuffer;
+
+/**
+ An `NSNumber` object containing a double; specifies the Douglas-Peucker
+ simplification tolerance. A greater value produces simpler geometries and
+ improves performance. The default value is 0.375.
+
+ This option corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-tolerance"><code>tolerance</code></a>
+ source property in the Mapbox Style Specification.
+ */
+extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance;
/**
`MGLShapeSource` is a map content source that supplies vector shapes to be
@@ -16,6 +103,10 @@ NS_ASSUME_NONNULL_BEGIN
`MGLStyle` object along with an `MGLVectorStyleLayer` object. The vector style
layer defines the appearance of any content supplied by the shape source. You
can update a shape source by setting its `shape` or `URL` property.
+
+ `MGLShapeSource` is optimized for data sets that change dynamically and fit
+ completely in memory. For large data sets that do not fit completely in memory,
+ use the `MGLComputedShapeSource` or `MGLVectorTileSource` class.
Each
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson"><code>geojson</code></a>
@@ -41,13 +132,21 @@ NS_ASSUME_NONNULL_BEGIN
```
*/
MGL_EXPORT
-@interface MGLShapeSource : MGLAbstractShapeSource
+@interface MGLShapeSource : MGLSource
#pragma mark Initializing a Source
/**
Returns a shape source with an identifier, URL, and dictionary of options for
the source.
+
+ This class supports the following options: `MGLShapeSourceOptionClustered`,
+ `MGLShapeSourceOptionClusterRadius`,
+ `MGLShapeSourceOptionMaximumZoomLevelForClustering`,
+ `MGLShapeSourceOptionMinimumZoomLevel`, `MGLShapeSourceOptionMaximumZoomLevel`,
+ `MGLShapeSourceOptionBuffer`, and
+ `MGLShapeSourceOptionSimplificationTolerance`. Shapes provided by a shape
+ source are not clipped or wrapped automatically.
@param identifier A string that uniquely identifies the source.
@param url An HTTP(S) URL, absolute file URL, or local file URL relative to the
@@ -60,6 +159,14 @@ MGL_EXPORT
/**
Returns a shape source with an identifier, a shape, and dictionary of options
for the source.
+
+ This class supports the following options: `MGLShapeSourceOptionClustered`,
+ `MGLShapeSourceOptionClusterRadius`,
+ `MGLShapeSourceOptionMaximumZoomLevelForClustering`,
+ `MGLShapeSourceOptionMinimumZoomLevel`, `MGLShapeSourceOptionMaximumZoomLevel`,
+ `MGLShapeSourceOptionBuffer`, and
+ `MGLShapeSourceOptionSimplificationTolerance`. Shapes provided by a shape
+ source are not clipped or wrapped automatically.
To specify attributes about the shape, use an instance of an `MGLShape`
subclass that conforms to the `MGLFeature` protocol, such as `MGLPointFeature`.
@@ -81,6 +188,14 @@ MGL_EXPORT
/**
Returns a shape source with an identifier, an array of features, and a dictionary
of options for the source.
+
+ This class supports the following options: `MGLShapeSourceOptionClustered`,
+ `MGLShapeSourceOptionClusterRadius`,
+ `MGLShapeSourceOptionMaximumZoomLevelForClustering`,
+ `MGLShapeSourceOptionMinimumZoomLevel`, `MGLShapeSourceOptionMaximumZoomLevel`,
+ `MGLShapeSourceOptionBuffer`, and
+ `MGLShapeSourceOptionSimplificationTolerance`. Shapes provided by a shape
+ source are not clipped or wrapped automatically.
Unlike `-initWithIdentifier:shapes:options:`, this method accepts `MGLFeature`
instances, such as `MGLPointFeature` objects, whose attributes you can use when
@@ -100,6 +215,14 @@ MGL_EXPORT
/**
Returns a shape source with an identifier, an array of shapes, and a dictionary of
options for the source.
+
+ This class supports the following options: `MGLShapeSourceOptionClustered`,
+ `MGLShapeSourceOptionClusterRadius`,
+ `MGLShapeSourceOptionMaximumZoomLevelForClustering`,
+ `MGLShapeSourceOptionMinimumZoomLevel`, `MGLShapeSourceOptionMaximumZoomLevel`,
+ `MGLShapeSourceOptionBuffer`, and
+ `MGLShapeSourceOptionSimplificationTolerance`. Shapes provided by a shape
+ source are not clipped or wrapped automatically.
Any `MGLFeature` instance passed into this initializer is treated as an ordinary
shape, causing any attributes to be inaccessible to an `MGLVectorStyleLayer` when
diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm
index 8fbb9a18ef..dcc3fd97f5 100644
--- a/platform/darwin/src/MGLShapeSource.mm
+++ b/platform/darwin/src/MGLShapeSource.mm
@@ -1,5 +1,4 @@
#import "MGLShapeSource_Private.h"
-#import "MGLAbstractShapeSource_Private.h"
#import "MGLStyle_Private.h"
#import "MGLMapView_Private.h"
@@ -14,7 +13,75 @@
#include <mbgl/style/sources/geojson_source.hpp>
#include <mbgl/renderer/renderer.hpp>
+const MGLShapeSourceOption MGLShapeSourceOptionBuffer = @"MGLShapeSourceOptionBuffer";
+const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius = @"MGLShapeSourceOptionClusterRadius";
+const MGLShapeSourceOption MGLShapeSourceOptionClustered = @"MGLShapeSourceOptionClustered";
+const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel = @"MGLShapeSourceOptionMaximumZoomLevel";
+const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering = @"MGLShapeSourceOptionMaximumZoomLevelForClustering";
+const MGLShapeSourceOption MGLShapeSourceOptionMinimumZoomLevel = @"MGLShapeSourceOptionMinimumZoomLevel";
+const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLShapeSourceOptionSimplificationTolerance";
+
+mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options) {
+ auto geoJSONOptions = mbgl::style::GeoJSONOptions();
+
+ if (NSNumber *value = options[MGLShapeSourceOptionMinimumZoomLevel]) {
+ if (![value isKindOfClass:[NSNumber class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"MGLShapeSourceOptionMaximumZoomLevel must be an NSNumber."];
+ }
+ geoJSONOptions.minzoom = value.integerValue;
+ }
+
+ if (NSNumber *value = options[MGLShapeSourceOptionMaximumZoomLevel]) {
+ if (![value isKindOfClass:[NSNumber class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"MGLShapeSourceOptionMaximumZoomLevel must be an NSNumber."];
+ }
+ geoJSONOptions.maxzoom = value.integerValue;
+ }
+
+ if (NSNumber *value = options[MGLShapeSourceOptionBuffer]) {
+ if (![value isKindOfClass:[NSNumber class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"MGLShapeSourceOptionBuffer must be an NSNumber."];
+ }
+ geoJSONOptions.buffer = value.integerValue;
+ }
+
+ if (NSNumber *value = options[MGLShapeSourceOptionSimplificationTolerance]) {
+ if (![value isKindOfClass:[NSNumber class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"MGLShapeSourceOptionSimplificationTolerance must be an NSNumber."];
+ }
+ geoJSONOptions.tolerance = value.doubleValue;
+ }
+ if (NSNumber *value = options[MGLShapeSourceOptionClusterRadius]) {
+ if (![value isKindOfClass:[NSNumber class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"MGLShapeSourceOptionClusterRadius must be an NSNumber."];
+ }
+ geoJSONOptions.clusterRadius = value.integerValue;
+ }
+
+ if (NSNumber *value = options[MGLShapeSourceOptionMaximumZoomLevelForClustering]) {
+ if (![value isKindOfClass:[NSNumber class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"MGLShapeSourceOptionMaximumZoomLevelForClustering must be an NSNumber."];
+ }
+ geoJSONOptions.clusterMaxZoom = value.integerValue;
+ }
+
+ if (NSNumber *value = options[MGLShapeSourceOptionClustered]) {
+ if (![value isKindOfClass:[NSNumber class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"MGLShapeSourceOptionClustered must be an NSNumber."];
+ }
+ geoJSONOptions.cluster = value.boolValue;
+ }
+
+ return geoJSONOptions;
+}
@interface MGLShapeSource ()
diff --git a/platform/darwin/src/MGLShapeSource_Private.h b/platform/darwin/src/MGLShapeSource_Private.h
index 1ea2c39b8e..0720074d1d 100644
--- a/platform/darwin/src/MGLShapeSource_Private.h
+++ b/platform/darwin/src/MGLShapeSource_Private.h
@@ -9,7 +9,7 @@ namespace mbgl {
}
}
-@interface MGLShapeSource (Private)
-@end
+MGL_EXPORT
+mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options);
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLSource.h b/platform/darwin/src/MGLSource.h
index 8d8c936833..7bbf02fa7c 100644
--- a/platform/darwin/src/MGLSource.h
+++ b/platform/darwin/src/MGLSource.h
@@ -16,10 +16,11 @@ NS_ASSUME_NONNULL_BEGIN
add and remove sources dynamically using methods such as
`-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`.
- 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.
+ Create instances of `MGLShapeSource`, `MGLComputedShapeSource`,
+ `MGLImageSource`, and the concrete subclasses of `MGLTileSource`
+ (`MGLVectorTileSource` and `MGLRasterTileSource`) 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.
*/
MGL_EXPORT
@interface MGLSource : NSObject
diff --git a/platform/darwin/src/MGLStyle.h b/platform/darwin/src/MGLStyle.h
index 0b360de8fc..6df627d7af 100644
--- a/platform/darwin/src/MGLStyle.h
+++ b/platform/darwin/src/MGLStyle.h
@@ -68,7 +68,7 @@ MGL_EXPORT
`-streetsStyleURLWithVersion:` method instead. Such details may change
significantly from version to version.
*/
-+ (NSURL *)streetsStyleURL;
+@property (class, nonatomic, readonly) NSURL *streetsStyleURL;
/**
Returns the URL to the given version of the
@@ -83,13 +83,7 @@ MGL_EXPORT
*/
+ (NSURL *)streetsStyleURLWithVersion:(NSInteger)version;
-/**
- Returns the URL to version 8 of the
- <a href="https://www.mapbox.com/blog/emerald-gl/">Mapbox Emerald</a> style.
-
- Emerald is a tactile style with subtle textures and dramatic hillshading.
- */
-+ (NSURL *)emeraldStyleURL __attribute__((deprecated("Create an NSURL object with the string “mapbox://styles/mapbox/emerald-v8”.")));
++ (NSURL *)emeraldStyleURL __attribute__((unavailable("Create an NSURL object with the string “mapbox://styles/mapbox/emerald-v8”.")));
/**
Returns the URL to the current version of the
@@ -104,7 +98,7 @@ MGL_EXPORT
`-outdoorsStyleURLWithVersion:` method instead. Such details may change
significantly from version to version.
*/
-+ (NSURL *)outdoorsStyleURL;
+@property (class, nonatomic, readonly) NSURL *outdoorsStyleURL;
/**
Returns the URL to the given version of the
@@ -128,7 +122,7 @@ MGL_EXPORT
`-lightStyleURLWithVersion:` method instead. Such details may change
significantly from version to version.
*/
-+ (NSURL *)lightStyleURL;
+@property (class, nonatomic, readonly) NSURL *lightStyleURL;
/**
Returns the URL to the given version of the
@@ -153,7 +147,7 @@ MGL_EXPORT
`-darkStyleURLWithVersion:` method instead. Such details may change
significantly from version to version.
*/
-+ (NSURL *)darkStyleURL;
+@property (class, nonatomic, readonly) NSURL *darkStyleURL;
/**
Returns the URL to the given version of the
@@ -178,7 +172,7 @@ MGL_EXPORT
`-satelliteStyleURLWithVersion:` method instead. Such details may change
significantly from version to version.
*/
-+ (NSURL *)satelliteStyleURL;
+@property (class, nonatomic, readonly) NSURL *satelliteStyleURL;
/**
Returns the URL to the given version of the
@@ -191,16 +185,8 @@ MGL_EXPORT
*/
+ (NSURL *)satelliteStyleURLWithVersion:(NSInteger)version;
-/**
- Returns the URL to version 8 of the
- <a href="https://www.mapbox.com/maps/satellite/">Mapbox Satellite Streets</a>
- style.
- Satellite Streets combines the high-resolution satellite and aerial imagery of
- Mapbox Satellite with unobtrusive labels and translucent roads from Mapbox
- Streets.
- */
-+ (NSURL *)hybridStyleURL __attribute__((deprecated("Use -satelliteStreetsStyleURL.")));
++ (NSURL *)hybridStyleURL __attribute__((unavailable("Use -satelliteStreetsStyleURL.")));
/**
Returns the URL to the current version of the
@@ -217,7 +203,7 @@ MGL_EXPORT
`-satelliteStreetsStyleURLWithVersion:` method instead. Such details may
change significantly from version to version.
*/
-+ (NSURL *)satelliteStreetsStyleURL;
+@property (class, nonatomic, readonly) NSURL *satelliteStreetsStyleURL;
/**
Returns the URL to the given version of the
@@ -232,39 +218,14 @@ MGL_EXPORT
*/
+ (NSURL *)satelliteStreetsStyleURLWithVersion:(NSInteger)version;
-/**
- Returns the URL to version 2 of the
- <a href="https://www.mapbox.com/blog/live-traffic-maps/">Mapbox Traffic Day</a>
- style.
- */
-+ (NSURL *)trafficDayStyleURL __attribute__((deprecated("Create an NSURL object with the string “mapbox://styles/mapbox/traffic-day-v2”.")));
-
-/**
- Returns the URL to the given version of the
- <a href="https://www.mapbox.com/blog/live-traffic-maps/">Mapbox Traffic Day</a>
- style as of publication.
-
- @param version A specific version of the style.
- */
-+ (NSURL *)trafficDayStyleURLWithVersion:(NSInteger)version __attribute__((deprecated("Create an NSURL object with the string “mapbox://styles/mapbox/traffic-day-v2”.")));;
++ (NSURL *)trafficDayStyleURL __attribute__((unavailable("Create an NSURL object with the string “mapbox://styles/mapbox/traffic-day-v2”.")));
-/**
- Returns the URL to the version 2 of the
- <a href="https://www.mapbox.com/blog/live-traffic-maps/">Mapbox Traffic Night</a>
- style.
++ (NSURL *)trafficDayStyleURLWithVersion:(NSInteger)version __attribute__((unavailable("Create an NSURL object with the string “mapbox://styles/mapbox/traffic-day-v2”.")));;
- */
-+ (NSURL *)trafficNightStyleURL __attribute__((deprecated("Create an NSURL object with the string “mapbox://styles/mapbox/traffic-night-v2”.")));
++ (NSURL *)trafficNightStyleURL __attribute__((unavailable("Create an NSURL object with the string “mapbox://styles/mapbox/traffic-night-v2”.")));
-/**
- Returns the URL to to the version 2 of the
- <a href="https://www.mapbox.com/blog/live-traffic-maps/">Mapbox Traffic Night</a>
- style as of publication.
-
- @param version A specific version of the style.
- */
-+ (NSURL *)trafficNightStyleURLWithVersion:(NSInteger)version __attribute__((deprecated("Create an NSURL object with the string “mapbox://styles/mapbox/traffic-night-v2”.")));
++ (NSURL *)trafficNightStyleURLWithVersion:(NSInteger)version __attribute__((unavailable("Create an NSURL object with the string “mapbox://styles/mapbox/traffic-night-v2”.")));
#pragma mark Accessing Metadata About the Style
@@ -455,25 +416,14 @@ MGL_EXPORT
#pragma mark Managing Style Classes
-/**
- 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 is non-functional.")));
-/**
- Support for style classes has been removed. This method always returns NO.
- */
-- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
+@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses __attribute__((unavailable("Support for style classes has been removed.")));
-/**
- Support for style classes has been removed. This method is a no-op.
- */
-- (void)addStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
+- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((unavailable("Support for style classes has been removed.")));
-/**
- Support for style classes has been removed. This method is a no-op.
- */
-- (void)removeStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
+- (void)addStyleClass:(NSString *)styleClass __attribute__((unavailable("Support for style classes has been removed.")));
+
+- (void)removeStyleClass:(NSString *)styleClass __attribute__((unavailable("Support for style classes has been removed.")));
#pragma mark Managing a Style’s Images
@@ -532,17 +482,22 @@ MGL_EXPORT
#pragma mark Localizing Map Content
/**
- A Boolean value that determines whether the style attempts to localize labels in
- the style into the system’s preferred language.
+ Attempts to localize labels in the style into the given locale.
+
+ This method automatically modifies the text property of any symbol style layer
+ in the style whose source is the
+ <a href="https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview">Mapbox Streets source</a>.
+ On iOS, the user can set the system’s preferred language in Settings, General
+ Settings, Language & Region. On macOS, the user can set the system’s preferred
+ language in the Language & Region pane of System Preferences.
- When this property is enabled, the style automatically modifies the text property
- of any symbol style layer whose source is the
- <a href="https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview">Mapbox
- Streets source</a>. On iOS, the user can set the system’s preferred language in
- Settings, General Settings, Language & Region. On macOS, the user can set the
- system’s preferred language in the Language & Region pane of System Preferences.
- */
-@property (nonatomic) BOOL localizesLabels;
+ @param locale The locale into which labels should be localized. To use the
+ system’s preferred language, if supported, specify `nil`. To use the local
+ language, specify a locale with the identifier `mul`.
+ */
+- (void)localizeLabelsIntoLocale:(nullable NSLocale *)locale;
+
+@property (nonatomic) BOOL localizesLabels __attribute__((unavailable("Use -localizeLabelsIntoLocale: instead.")));
@end
diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm
index f6fc5533be..867ac6c451 100644
--- a/platform/darwin/src/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
@@ -18,9 +18,8 @@
#import "MGLSource_Private.h"
#import "MGLLight_Private.h"
#import "MGLTileSource_Private.h"
-#import "MGLVectorSource.h"
-#import "MGLVectorSource_Private.h"
-#import "MGLRasterSource.h"
+#import "MGLVectorTileSource_Private.h"
+#import "MGLRasterTileSource.h"
#import "MGLRasterDEMSource.h"
#import "MGLShapeSource.h"
#import "MGLImageSource.h"
@@ -83,6 +82,7 @@
@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;
@end
@@ -116,64 +116,16 @@ MGL_DEFINE_STYLE(satelliteStreets, satellite-streets)
// Make sure all the styles listed in mbgl::util::default_styles::orderedStyles
// are defined above and also declared in MGLStyle.h.
-static_assert(8 == mbgl::util::default_styles::numOrderedStyles,
+static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
"mbgl::util::default_styles::orderedStyles and MGLStyle have different numbers of styles.");
-// Hybrid has been renamed Satellite Streets, so the last Hybrid version is hard-coded here.
-static NSURL *MGLStyleURL_hybrid;
-+ (NSURL *)hybridStyleURL {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- MGLStyleURL_hybrid = [NSURL URLWithString:@"mapbox://styles/mapbox/satellite-hybrid-v8"];
- });
- return MGLStyleURL_hybrid;
-}
-
-// Emerald is no longer getting new versions as a default style, so the current version is hard-coded here.
-static NSURL *MGLStyleURL_emerald;
-+ (NSURL *)emeraldStyleURL {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- MGLStyleURL_emerald = [NSURL URLWithString:@"mapbox://styles/mapbox/emerald-v8"];
- });
- return MGLStyleURL_emerald;
-}
-
-// Traffic Day is no longer getting new versions as a default style, so the current version is hard-coded here.
-static NSURL *MGLStyleURL_trafficDay;
-+ (NSURL *)trafficDayStyleURL {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- MGLStyleURL_trafficDay = [NSURL URLWithString:@"mapbox://styles/mapbox/traffic-day-v2"];
- });
- return MGLStyleURL_trafficDay;
-}
-
-+ (NSURL *)trafficDayStyleURLWithVersion:(NSInteger)version {
- return [NSURL URLWithString:[@"mapbox://styles/mapbox/traffic-day-v" stringByAppendingFormat:@"%li", (long)version]];
-}
-
-// Traffic Night is no longer getting new versions as a default style, so the current version is hard-coded here.
-static NSURL *MGLStyleURL_trafficNight;
-+ (NSURL *)trafficNightStyleURL {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- MGLStyleURL_trafficNight = [NSURL URLWithString:@"mapbox://styles/mapbox/traffic-night-v2"];
- });
- return MGLStyleURL_trafficNight;
-}
-
-+ (NSURL *)trafficNightStyleURLWithVersion:(NSInteger)version {
- return [NSURL URLWithString:[@"mapbox://styles/mapbox/traffic-night-v" stringByAppendingFormat:@"%li", (long)version]];
-}
-
-
#pragma mark -
- (instancetype)initWithRawStyle:(mbgl::style::Style *)rawStyle mapView:(MGLMapView *)mapView {
if (self = [super init]) {
_mapView = mapView;
_rawStyle = rawStyle;
+ _openGLLayers = [NSMutableDictionary dictionary];
_localizedLayersByIdentifier = [NSMutableDictionary dictionary];
}
return self;
@@ -232,11 +184,11 @@ static NSURL *MGLStyleURL_trafficNight;
// TODO: Fill in options specific to the respective source classes
// https://github.com/mapbox/mapbox-gl-native/issues/6584
if (auto vectorSource = rawSource->as<mbgl::style::VectorSource>()) {
- return [[MGLVectorSource alloc] initWithRawSource:vectorSource mapView:self.mapView];
+ return [[MGLVectorTileSource alloc] initWithRawSource:vectorSource mapView:self.mapView];
} else if (auto geoJSONSource = rawSource->as<mbgl::style::GeoJSONSource>()) {
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];
+ return [[MGLRasterTileSource alloc] initWithRawSource:rasterSource mapView:self.mapView];
} else if (auto rasterDEMSource = rawSource->as<mbgl::style::RasterDEMSource>()) {
return [[MGLRasterDEMSource alloc] initWithRawSource:rasterDEMSource mapView:self.mapView];
} else if (auto imageSource = rawSource->as<mbgl::style::ImageSource>()) {
@@ -534,38 +486,6 @@ static NSURL *MGLStyleURL_trafficNight;
[self didChangeValueForKey:@"layers"];
}
-#pragma mark Style classes
-
-- (NS_ARRAY_OF(NSString *) *)styleClasses
-{
- return @[];
-}
-
-- (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses
-{
-}
-
-- (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration
-{
-}
-
-- (NSUInteger)countOfStyleClasses {
- return 0;
-}
-
-- (BOOL)hasStyleClass:(NSString *)styleClass
-{
- return NO;
-}
-
-- (void)addStyleClass:(NSString *)styleClass
-{
-}
-
-- (void)removeStyleClass:(NSString *)styleClass
-{
-}
-
#pragma mark Style images
- (void)setImage:(MGLImage *)image forName:(NSString *)name
@@ -650,79 +570,33 @@ static NSURL *MGLStyleURL_trafficNight;
#pragma mark Mapbox Streets source introspection
-- (void)setLocalizesLabels:(BOOL)localizesLabels
-{
- if (_localizesLabels != localizesLabels) {
- _localizesLabels = localizesLabels;
- } else {
- return;
- }
+- (void)localizeLabelsIntoLocale:(nullable NSLocale *)locale {
+ NSSet<MGLVectorTileSource *> *streetsSources =
+ [self.sources filteredSetUsingPredicate:
+ [NSPredicate predicateWithBlock:^BOOL(MGLVectorTileSource * _Nullable source, NSDictionary<NSString *, id> * _Nullable bindings) {
+ return [source isKindOfClass:[MGLVectorTileSource class]] && [source isMapboxStreets];
+ }]];
+ NSSet<NSString *> *streetsSourceIdentifiers = [streetsSources valueForKey:@"identifier"];
- if (_localizesLabels) {
- NSString *preferredLanguage = [MGLVectorSource preferredMapboxStreetsLanguage];
- NSMutableDictionary *localizedKeysByKeyBySourceIdentifier = [NSMutableDictionary dictionary];
- for (MGLSymbolStyleLayer *layer in self.layers) {
- if (![layer isKindOfClass:[MGLSymbolStyleLayer class]]) {
- continue;
- }
-
- MGLVectorSource *source = (MGLVectorSource *)[self sourceWithIdentifier:layer.sourceIdentifier];
- if (![source isKindOfClass:[MGLVectorSource class]] || !source.mapboxStreets) {
- continue;
- }
-
- NSDictionary *localizedKeysByKey = localizedKeysByKeyBySourceIdentifier[layer.sourceIdentifier];
- if (!localizedKeysByKey) {
- localizedKeysByKey = localizedKeysByKeyBySourceIdentifier[layer.sourceIdentifier] = [source localizedKeysByKeyForPreferredLanguage:preferredLanguage];
- }
-
- NSString *(^stringByLocalizingString)(NSString *) = ^ NSString * (NSString *string) {
- NSMutableString *localizedString = string.mutableCopy;
- [localizedKeysByKey enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull localizedKey, BOOL * _Nonnull stop) {
- NSAssert([key isKindOfClass:[NSString class]], @"key is not a string");
- NSAssert([localizedKey isKindOfClass:[NSString class]], @"localizedKey is not a string");
- [localizedString replaceOccurrencesOfString:[NSString stringWithFormat:@"{%@}", key]
- withString:[NSString stringWithFormat:@"{%@}", localizedKey]
- options:0
- range:NSMakeRange(0, localizedString.length)];
- }];
- return localizedString;
- };
-
- if (layer.text.expressionType == NSConstantValueExpressionType) {
- NSString *textField = layer.text.constantValue;
- NSString *localizingString = stringByLocalizingString(textField);
- if (![textField isEqualToString:localizingString]) {
- MGLTextLanguage *textLanguage = [[MGLTextLanguage alloc] initWithTextLanguage:textField
- updatedTextField:localizingString];
- [self.localizedLayersByIdentifier setObject:@{ textField : textLanguage } forKey:layer.identifier];
- layer.text = [NSExpression expressionForConstantValue:localizingString];
- }
- }
+ for (MGLSymbolStyleLayer *layer in self.layers) {
+ if (![layer isKindOfClass:[MGLSymbolStyleLayer class]]) {
+ continue;
+ }
+ if (![streetsSourceIdentifiers containsObject:layer.sourceIdentifier]) {
+ continue;
}
- } else {
- [self.localizedLayersByIdentifier enumerateKeysAndObjectsUsingBlock:^(NSString *identifier, NSDictionary<NSObject *, MGLTextLanguage *> *textFields, BOOL *done) {
- MGLSymbolStyleLayer *layer = (MGLSymbolStyleLayer *)[self.mapView.style layerWithIdentifier:identifier];
-
- if (layer.text.expressionType == NSConstantValueExpressionType) {
- NSString *textField = layer.text.constantValue;
- [textFields enumerateKeysAndObjectsUsingBlock:^(NSObject *originalLanguage, MGLTextLanguage *textLanguage, BOOL *done) {
- if ([textLanguage.updatedTextField isEqualToString:textField]) {
- layer.text = [NSExpression expressionForConstantValue:textLanguage.originalTextField];
- }
- }];
-
- }
- }];
-
- self.localizedLayersByIdentifier = [NSMutableDictionary dictionary];
+ NSExpression *text = layer.text;
+ NSExpression *localizedText = [text mgl_expressionLocalizedIntoLocale:locale];
+ if (![localizedText isEqual:text]) {
+ layer.text = localizedText;
+ }
}
}
-- (NS_SET_OF(MGLVectorSource *) *)mapboxStreetsSources {
- return [self.sources objectsPassingTest:^BOOL (__kindof MGLVectorSource * _Nonnull source, BOOL * _Nonnull stop) {
- return [source isKindOfClass:[MGLVectorSource class]] && source.mapboxStreets;
+- (NS_SET_OF(MGLVectorTileSource *) *)mapboxStreetsSources {
+ return [self.sources objectsPassingTest:^BOOL (__kindof MGLVectorTileSource * _Nonnull source, BOOL * _Nonnull stop) {
+ return [source isKindOfClass:[MGLVectorTileSource class]] && source.mapboxStreets;
}];
}
diff --git a/platform/darwin/src/MGLStyleLayer.mm.ejs b/platform/darwin/src/MGLStyleLayer.mm.ejs
index ac7676a1cc..42940083b5 100644
--- a/platform/darwin/src/MGLStyleLayer.mm.ejs
+++ b/platform/darwin/src/MGLStyleLayer.mm.ejs
@@ -136,7 +136,12 @@ namespace mbgl {
if (propertyValue.isUndefined()) {
propertyValue = self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>();
}
+<% if (property.type === 'string') { -%>
+ NSExpression *expression = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toExpression(propertyValue);
+ return expression.mgl_expressionByReplacingTokensWithKeyPaths;
+<% } else { -%>
return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toExpression(propertyValue);
+<% } -%>
}
<% if (property.original) { -%>
@@ -174,7 +179,12 @@ namespace mbgl {
if (propertyValue.isUndefined()) {
propertyValue = self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>();
}
+<% if (property.type === 'string') { -%>
+ NSExpression *expression = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toExpression(propertyValue);
+ return expression.mgl_expressionByReplacingTokensWithKeyPaths;
+<% } else { -%>
return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toExpression(propertyValue);
+<% } -%>
}
<% if (property["transition"]) { -%>
diff --git a/platform/darwin/src/MGLStyleValue.h b/platform/darwin/src/MGLStyleValue.h
index f6e9c51729..65f89c5909 100644
--- a/platform/darwin/src/MGLStyleValue.h
+++ b/platform/darwin/src/MGLStyleValue.h
@@ -8,13 +8,13 @@ NS_ASSUME_NONNULL_BEGIN
typedef NSString *MGLStyleFunctionOption NS_STRING_ENUM NS_UNAVAILABLE;
-extern MGL_EXPORT const MGLStyleFunctionOption MGLStyleFunctionOptionInterpolationBase __attribute__((unavailable("Use NSExpression instead, applying the mgl_interpolateWithCurveType:parameters:stops: function with a curve type of “exponential” and a non-nil parameter.")));
+extern MGL_EXPORT const MGLStyleFunctionOption MGLStyleFunctionOptionInterpolationBase __attribute__((unavailable("Use NSExpression instead, applying the mgl_interpolate:withCurveType:parameters:stops: function with a curve type of “exponential” and a non-nil parameter.")));
extern MGL_EXPORT const MGLStyleFunctionOption MGLStyleFunctionOptionDefaultValue __attribute__((unavailable("Use +[NSExpression expressionForConditional:trueExpression:falseExpression:] instead.")));
typedef NS_ENUM(NSUInteger, MGLInterpolationMode) {
- MGLInterpolationModeExponential __attribute__((unavailable("Use NSExpression instead, applying the mgl_interpolateWithCurveType:parameters:stops: function with a curve type of “exponential”."))) = 0,
- MGLInterpolationModeInterval __attribute__((unavailable("Use NSExpression instead, calling the mgl_stepWithMinimum:stops: function."))),
+ MGLInterpolationModeExponential __attribute__((unavailable("Use NSExpression instead, applying the mgl_interpolate:withCurveType:parameters:stops: function with a curve type of “exponential”."))) = 0,
+ MGLInterpolationModeInterval __attribute__((unavailable("Use NSExpression instead, calling the mgl_step:from:stops: function."))),
MGLInterpolationModeCategorical __attribute__((unavailable("Use NSExpression instead."))),
MGLInterpolationModeIdentity __attribute__((unavailable("Use +[NSExpression expressionForKeyPath:] instead.")))
} __attribute__((unavailable("Use NSExpression instead.")));
@@ -29,19 +29,19 @@ MGL_EXPORT __attribute__((unavailable("Use +[NSExpression expressionForConstantV
@compatibility_alias MGLStyleConstantValue MGLConstantStyleValue;
-MGL_EXPORT __attribute__((unavailable("Use NSExpression instead, calling the mgl_stepWithMinimum:stops: or mgl_interpolateWithCurveType:parameters:stops: function.")))
+MGL_EXPORT __attribute__((unavailable("Use NSExpression instead, calling the mgl_step:from:stops: or mgl_interpolate:withCurveType:parameters:stops: function.")))
@interface MGLStyleFunction<T> : MGLStyleValue<T>
@end
-MGL_EXPORT __attribute__((unavailable("Use NSExpression instead, applying the mgl_stepWithMinimum:stops: or mgl_interpolateWithCurveType:parameters:stops: function to the $zoomLevel variable.")))
+MGL_EXPORT __attribute__((unavailable("Use NSExpression instead, applying the mgl_step:from:stops: or mgl_interpolate:withCurveType:parameters:stops: function to the $zoomLevel variable.")))
@interface MGLCameraStyleFunction<T> : MGLStyleFunction<T>
@end
-MGL_EXPORT __attribute__((unavailable("Use NSExpression instead, applying the mgl_stepWithMinimum:stops: or mgl_interpolateWithCurveType:parameters:stops: function to a key path expression.")))
+MGL_EXPORT __attribute__((unavailable("Use NSExpression instead, applying the mgl_step:from:stops: or mgl_interpolate:withCurveType:parameters:stops: function to a key path expression.")))
@interface MGLSourceStyleFunction<T> : MGLStyleFunction<T>
@end
-MGL_EXPORT __attribute__((unavailable("Use a NSExpression instead with nested mgl_stepWithMinimum:stops: or mgl_interpolateWithCurveType:parameters:stops: function calls.")))
+MGL_EXPORT __attribute__((unavailable("Use a NSExpression instead with nested mgl_step:from:stops: or mgl_interpolate:withCurveType:parameters:stops: function calls.")))
@interface MGLCompositeStyleFunction<T> : MGLStyleFunction<T>
@end
diff --git a/platform/darwin/src/MGLStyleValue.mm b/platform/darwin/src/MGLStyleValue.mm
index 74e1926f79..5103b5f5cf 100644
--- a/platform/darwin/src/MGLStyleValue.mm
+++ b/platform/darwin/src/MGLStyleValue.mm
@@ -5,7 +5,7 @@
const MGLStyleFunctionOption MGLStyleFunctionOptionInterpolationBase = @"MGLStyleFunctionOptionInterpolationBase";
const MGLStyleFunctionOption MGLStyleFunctionOptionDefaultValue = @"MGLStyleFunctionOptionDefaultValue";
-id MGLJSONObjectFromMBGLValue(const mbgl::style::expression::Value &value) {
+id MGLJSONObjectFromMBGLValue(const mbgl::Value &value) {
return value.match([](const mbgl::NullValue) -> id {
return [NSNull null];
}, [](const bool value) {
@@ -24,98 +24,23 @@ id MGLJSONObjectFromMBGLValue(const mbgl::style::expression::Value &value) {
std::array<float, 3> spherical = value.getSpherical();
MGLSphericalPosition position = MGLSphericalPositionMake(spherical[0], spherical[1], spherical[2]);
return [NSValue valueWithMGLSphericalPosition:position];
- }, [&](const std::vector<mbgl::style::expression::Value> &vector) {
+ }, [&](const std::vector<mbgl::Value> &vector) {
NSMutableArray *array = [NSMutableArray arrayWithCapacity:vector.size()];
for (auto value : vector) {
[array addObject:MGLJSONObjectFromMBGLValue(value)];
}
- return @[@"literal", array];
- }, [&](const std::unordered_map<std::string, mbgl::style::expression::Value> &map) {
+ return array;
+ }, [&](const std::unordered_map<std::string, mbgl::Value> &map) {
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:map.size()];
for (auto &item : map) {
dictionary[@(item.first.c_str())] = MGLJSONObjectFromMBGLValue(item.second);
}
- return @[@"literal", dictionary];
+ return dictionary;
}, [](const auto &) -> id {
return nil;
});
}
id MGLJSONObjectFromMBGLExpression(const mbgl::style::expression::Expression &mbglExpression) {
- using namespace mbgl::style::expression;
- if (auto literalExpression = dynamic_cast<const Literal *>(&mbglExpression)) {
- auto result = literalExpression->evaluate({ nullptr });
- return result ? MGLJSONObjectFromMBGLValue(*result) : nil;
- }
- if (auto assertExpression = dynamic_cast<const ArrayAssertion *>(&mbglExpression)) {
- NSMutableArray *inputs = [NSMutableArray array];
- assertExpression->eachChild([&](const Expression &child) {
- [inputs addObject:MGLJSONObjectFromMBGLExpression(child)];
- });
- return @[@"literal", inputs.lastObject];
- }
- if (auto assertExpression = dynamic_cast<const Assertion *>(&mbglExpression)) {
- NSMutableArray *inputs = [NSMutableArray array];
- assertExpression->eachChild([&](const Expression &child) {
- [inputs addObject:MGLJSONObjectFromMBGLExpression(child)];
- });
- return inputs.firstObject;
- }
- if (auto compoundExpression = dynamic_cast<const CompoundExpressionBase *>(&mbglExpression)) {
- const std::string name = compoundExpression->getName();
- mbgl::optional<std::size_t> parameterCount = compoundExpression->getParameterCount();
- NSMutableArray *expressionObject = parameterCount ? [NSMutableArray arrayWithCapacity:*parameterCount + 1] : [NSMutableArray array];
- [expressionObject addObject:@(name.c_str())];
- compoundExpression->eachChild([&](const Expression &child) {
- [expressionObject addObject:MGLJSONObjectFromMBGLExpression(child)];
- });
- return expressionObject;
- }
- if (auto stepExpression = dynamic_cast<const Step *>(&mbglExpression)) {
- auto &input = stepExpression->getInput();
- NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"step", MGLJSONObjectFromMBGLExpression(*input.get()), nil];
- stepExpression->eachStop([&](double stop, const Expression &child) {
- [expressionObject addObject:@(stop)];
- [expressionObject addObject:MGLJSONObjectFromMBGLExpression(child)];
- });
- if ([expressionObject[2] isEqual:@(-INFINITY)]) {
- [expressionObject removeObjectAtIndex:2];
- }
- return expressionObject;
- }
- if (auto interpolateExpression = dynamic_cast<const InterpolateBase *>(&mbglExpression)) {
- auto &interpolator = interpolateExpression->getInterpolator();
- auto &input = interpolateExpression->getInput();
- NSArray *interpolatorObject;
- if (interpolator.is<ExponentialInterpolator>()) {
- auto exponentialInterpolator = interpolator.get<ExponentialInterpolator>();
- interpolatorObject = exponentialInterpolator.base == 1 ? @[@"linear"] : @[@"exponential", @(exponentialInterpolator.base)];
- } else if (interpolator.is<CubicBezierInterpolator>()) {
- auto cubicBezierInterpolator = interpolator.get<CubicBezierInterpolator>();
- auto bezier = cubicBezierInterpolator.ub;
- interpolatorObject = @[
- @"cubic-bezier",
- @(bezier.getP1().first), @(bezier.getP1().second),
- @(bezier.getP2().first), @(bezier.getP2().second),
- ];
- } else {
- NSCAssert(NO, @"Unrecognized interpolator type.");
- }
- NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"interpolate", interpolatorObject, MGLJSONObjectFromMBGLExpression(*input.get()), nil];
- interpolateExpression->eachStop([&](double stop, const Expression &child) {
- [expressionObject addObject:@(stop)];
- [expressionObject addObject:MGLJSONObjectFromMBGLExpression(child)];
- });
- return expressionObject;
- }
- if (auto caseExpression = dynamic_cast<const Case *>(&mbglExpression)) {
- NSMutableArray *expressionObject = [NSMutableArray arrayWithObject:@"case"];
- caseExpression->eachChild([&](const Expression &child) {
- [expressionObject addObject:MGLJSONObjectFromMBGLExpression(child)];
- });
- return expressionObject;
- }
- NSCAssert(NO, @"Unrecognized expression type.");
- return nil;
+ return MGLJSONObjectFromMBGLValue(mbglExpression.serialize());
}
-
diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h
index 5124c29a90..cc63793d0d 100644
--- a/platform/darwin/src/MGLStyleValue_Private.h
+++ b/platform/darwin/src/MGLStyleValue_Private.h
@@ -58,7 +58,7 @@ public:
if (mbglValue.isUndefined()) {
return nil;
}
- return [NSExpression mgl_expressionWithJSONObject:MGLJSONObjectFromMBGLExpression(mbglValue.getExpression())];
+ return [NSExpression expressionWithMGLJSONObject:MGLJSONObjectFromMBGLExpression(mbglValue.getExpression())];
}
/**
@@ -333,15 +333,15 @@ private: // Private utilities for converting from mbgl to mgl values
}
NSExpression *operator()(const mbgl::style::CameraFunction<MBGLType> &mbglValue) const {
- return [NSExpression mgl_expressionWithJSONObject:MGLJSONObjectFromMBGLExpression(mbglValue.getExpression())];
+ return [NSExpression expressionWithMGLJSONObject:MGLJSONObjectFromMBGLExpression(mbglValue.getExpression())];
}
NSExpression *operator()(const mbgl::style::SourceFunction<MBGLType> &mbglValue) const {
- return [NSExpression mgl_expressionWithJSONObject:MGLJSONObjectFromMBGLExpression(mbglValue.getExpression())];
+ return [NSExpression expressionWithMGLJSONObject:MGLJSONObjectFromMBGLExpression(mbglValue.getExpression())];
}
NSExpression *operator()(const mbgl::style::CompositeFunction<MBGLType> &mbglValue) const {
- return [NSExpression mgl_expressionWithJSONObject:MGLJSONObjectFromMBGLExpression(mbglValue.getExpression())];
+ return [NSExpression expressionWithMGLJSONObject:MGLJSONObjectFromMBGLExpression(mbglValue.getExpression())];
}
};
};
diff --git a/platform/darwin/src/MGLStyle_Private.h b/platform/darwin/src/MGLStyle_Private.h
index 4cbe953a44..24466b8018 100644
--- a/platform/darwin/src/MGLStyle_Private.h
+++ b/platform/darwin/src/MGLStyle_Private.h
@@ -14,7 +14,7 @@ namespace mbgl {
@class MGLAttributionInfo;
@class MGLMapView;
@class MGLOpenGLStyleLayer;
-@class MGLVectorSource;
+@class MGLVectorTileSource;
@class MGLVectorStyleLayer;
@interface MGLStyle (Private)
@@ -25,7 +25,7 @@ namespace mbgl {
@property (nonatomic, readonly) mbgl::style::Style *rawStyle;
- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
-
+@property (nonatomic, readonly, strong) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLOpenGLStyleLayer *) *openGLLayers;
- (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration;
@end
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h
index 1017db5442..e27f039b75 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.h
+++ b/platform/darwin/src/MGLSymbolStyleLayer.h
@@ -319,9 +319,10 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslationAnchor) {
An `MGLSymbolStyleLayer` is a style layer that renders icon and text labels at
points or along lines on the map.
- Use a symbol style layer to configure the visual appearance of labels for
- features in vector tiles loaded by an `MGLVectorSource` object or `MGLShape` or
- `MGLFeature` instances in an `MGLShapeSource` object.
+ Use a symbol style layer to configure the visual appearance of feature labels.
+ These features can come from vector tiles loaded by an `MGLVectorTileSource`
+ object, or they can be `MGLShape` or `MGLFeature` instances in an
+ `MGLShapeSource` or `MGLComputedShapeSource` object.
You can access an existing symbol style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
@@ -460,11 +461,15 @@ MGL_EXPORT
@property (nonatomic, null_resettable) NSExpression *iconIgnorePlacement __attribute__((unavailable("Use iconIgnoresPlacement instead.")));
/**
- Name of image in sprite to use for drawing an image background. Within literal
- values, attribute names enclosed in curly brackets (e.g. `{token}`) are
- replaced with the value of the named attribute. Expressions do not support this
- syntax; for equivalent functionality in expressions, use
- `stringByAppendingString:` and key path expressions.
+ Name of a style image to use for drawing an image background.
+
+ Use the `+[MGLStyle setImage:forName:]` method to associate an image with a
+ name that you can set this property to.
+
+ Within a constant string value, a feature attribute name enclosed in curly
+ braces (e.g., `{token}`) is replaced with the value of the named attribute.
+ Tokens inside non-constant expressions are ignored; instead, use `mgl_join:`
+ and key path expressions.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-image"><code>icon-image</code></a>
@@ -559,14 +564,14 @@ MGL_EXPORT
This property is measured in points.
The default value of this property is an expression that evaluates to the float
- `2`. Set this property to `nil` to reset it to the default value.
+ 2. 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 expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -610,7 +615,7 @@ MGL_EXPORT
This property is measured in degrees.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. 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.
@@ -673,7 +678,7 @@ MGL_EXPORT
This property is measured in factor of the original icon sizes.
The default value of this property is an expression that evaluates to the float
- `1`. Set this property to `nil` to reset it to the default value.
+ 1. 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.
@@ -684,7 +689,7 @@ MGL_EXPORT
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -853,7 +858,7 @@ MGL_EXPORT
This property is measured in degrees.
The default value of this property is an expression that evaluates to the float
- `45`. Set this property to `nil` to reset it to the default value.
+ 45. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `text` is non-`nil`, and
`symbolPlacement` is set to an expression that evaluates to `line`. Otherwise,
@@ -885,7 +890,7 @@ MGL_EXPORT
This property is measured in ems.
The default value of this property is an expression that evaluates to the float
- `10`. Set this property to `nil` to reset it to the default value.
+ 10. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
@@ -896,7 +901,7 @@ MGL_EXPORT
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -968,14 +973,14 @@ MGL_EXPORT
This property is measured in points.
The default value of this property is an expression that evaluates to the float
- `250`. Set this property to `nil` to reset it to the default value.
+ 250. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `symbolPlacement` is set to an
expression that evaluates to `line`. Otherwise, it is ignored.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 1
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -987,10 +992,12 @@ MGL_EXPORT
@property (nonatomic, null_resettable) NSExpression *symbolSpacing;
/**
- Value to use for a text label. Within literal values, attribute names enclosed
- in curly brackets (e.g. `{token}`) are replaced with the value of the named
- attribute. Expressions do not support this syntax; for equivalent functionality
- in expressions, use `stringByAppendingString:` and key path expressions.
+ Value to use for a text label.
+
+ Within a constant string value, a feature attribute name enclosed in curly
+ braces (e.g., `{token}`) is replaced with the value of the named attribute.
+ Tokens inside non-constant expressions are ignored; instead, use `mgl_join:`
+ and key path expressions.
The default value of this property is an expression that evaluates to the empty
string. Set this property to `nil` to reset it to the default value.
@@ -1122,7 +1129,7 @@ MGL_EXPORT
This property is measured in points.
The default value of this property is an expression that evaluates to the float
- `16`. Set this property to `nil` to reset it to the default value.
+ 16. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
@@ -1133,7 +1140,7 @@ MGL_EXPORT
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -1212,7 +1219,7 @@ MGL_EXPORT
This property is measured in ems.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
@@ -1234,7 +1241,7 @@ MGL_EXPORT
This property is measured in ems.
The default value of this property is an expression that evaluates to the float
- `1.2`. Set this property to `nil` to reset it to the default value.
+ 1.2. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
@@ -1331,14 +1338,14 @@ MGL_EXPORT
This property is measured in points.
The default value of this property is an expression that evaluates to the float
- `2`. Set this property to `nil` to reset it to the default value.
+ 2. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -1382,7 +1389,7 @@ MGL_EXPORT
This property is measured in degrees.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
@@ -1463,6 +1470,7 @@ MGL_EXPORT
#pragma mark - Accessing the Paint Attributes
+#if TARGET_OS_IPHONE
/**
The tint color to apply to the icon. The `iconImageName` property must be set
to a template image.
@@ -1484,6 +1492,29 @@ MGL_EXPORT
feature attributes
*/
@property (nonatomic, null_resettable) NSExpression *iconColor;
+#else
+/**
+ The tint color to apply to the icon. The `iconImageName` property must be set
+ to a template image.
+
+ The default value of this property is an expression that evaluates to
+ `NSColor.blackColor`. 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 expression containing any of the following:
+
+ * Constant `NSColor` values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$zoomLevel` variable and/or
+ feature attributes
+ */
+@property (nonatomic, null_resettable) NSExpression *iconColor;
+#endif
/**
The transition affecting any changes to this layer’s `iconColor` property.
@@ -1498,14 +1529,14 @@ MGL_EXPORT
This property is measured in points.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. 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 expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -1521,6 +1552,7 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition iconHaloBlurTransition;
+#if TARGET_OS_IPHONE
/**
The color of the icon’s halo. The `iconImageName` property must be set to a
template image.
@@ -1542,6 +1574,29 @@ MGL_EXPORT
feature attributes
*/
@property (nonatomic, null_resettable) NSExpression *iconHaloColor;
+#else
+/**
+ The color of the icon’s halo. The `iconImageName` property must be set to a
+ template image.
+
+ The default value of this property is an expression that evaluates to
+ `NSColor.clearColor`. 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 expression containing any of the following:
+
+ * Constant `NSColor` values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$zoomLevel` variable and/or
+ feature attributes
+ */
+@property (nonatomic, null_resettable) NSExpression *iconHaloColor;
+#endif
/**
The transition affecting any changes to this layer’s `iconHaloColor` property.
@@ -1556,14 +1611,14 @@ MGL_EXPORT
This property is measured in points.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. 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 expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -1583,14 +1638,14 @@ MGL_EXPORT
The opacity at which the icon will be drawn.
The default value of this property is an expression that evaluates to the float
- `1`. Set this property to `nil` to reset it to the default value.
+ 1. 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 expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between 0 and 1 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -1707,6 +1762,7 @@ MGL_EXPORT
@property (nonatomic, null_resettable) NSExpression *iconTranslateAnchor __attribute__((unavailable("Use iconTranslationAnchor instead.")));
+#if TARGET_OS_IPHONE
/**
The color with which the text will be drawn.
@@ -1727,6 +1783,28 @@ MGL_EXPORT
feature attributes
*/
@property (nonatomic, null_resettable) NSExpression *textColor;
+#else
+/**
+ The color with which the text will be drawn.
+
+ The default value of this property is an expression that evaluates to
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant `NSColor` values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$zoomLevel` variable and/or
+ feature attributes
+ */
+@property (nonatomic, null_resettable) NSExpression *textColor;
+#endif
/**
The transition affecting any changes to this layer’s `textColor` property.
@@ -1741,14 +1819,14 @@ MGL_EXPORT
This property is measured in points.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -1764,6 +1842,7 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition textHaloBlurTransition;
+#if TARGET_OS_IPHONE
/**
The color of the text's halo, which helps it stand out from backgrounds.
@@ -1784,6 +1863,28 @@ MGL_EXPORT
feature attributes
*/
@property (nonatomic, null_resettable) NSExpression *textHaloColor;
+#else
+/**
+ The color of the text's halo, which helps it stand out from backgrounds.
+
+ The default value of this property is an expression that evaluates to
+ `NSColor.clearColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `text` is non-`nil`. Otherwise,
+ it is ignored.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant `NSColor` values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$zoomLevel` variable and/or
+ feature attributes
+ */
+@property (nonatomic, null_resettable) NSExpression *textHaloColor;
+#endif
/**
The transition affecting any changes to this layer’s `textHaloColor` property.
@@ -1799,14 +1900,14 @@ MGL_EXPORT
This property is measured in points.
The default value of this property is an expression that evaluates to the float
- `0`. Set this property to `nil` to reset it to the default value.
+ 0. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values no less than 0
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
@@ -1826,14 +1927,14 @@ MGL_EXPORT
The opacity at which the text will be drawn.
The default value of this property is an expression that evaluates to the float
- `1`. Set this property to `nil` to reset it to the default value.
+ 1. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
You can set this property to an expression containing any of the following:
- * Constant numeric values
+ * Constant numeric values between 0 and 1 inclusive
* Predefined functions, including mathematical and string operators
* Conditional expressions
* Variable assignments and references to assigned variables
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.mm b/platform/darwin/src/MGLSymbolStyleLayer.mm
index 24d6643e6c..0d9fac4808 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.mm
+++ b/platform/darwin/src/MGLSymbolStyleLayer.mm
@@ -233,7 +233,8 @@ namespace mbgl {
if (propertyValue.isUndefined()) {
propertyValue = self.rawLayer->getDefaultIconImage();
}
- return MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ NSExpression *expression = MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ return expression.mgl_expressionByReplacingTokensWithKeyPaths;
}
- (void)setIconImage:(NSExpression *)iconImage {
@@ -578,7 +579,8 @@ namespace mbgl {
if (propertyValue.isUndefined()) {
propertyValue = self.rawLayer->getDefaultTextField();
}
- return MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ NSExpression *expression = MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ return expression.mgl_expressionByReplacingTokensWithKeyPaths;
}
- (void)setTextField:(NSExpression *)textField {
diff --git a/platform/darwin/src/MGLTileSource.h b/platform/darwin/src/MGLTileSource.h
index 2d75fa14d8..4bf09026f2 100644
--- a/platform/darwin/src/MGLTileSource.h
+++ b/platform/darwin/src/MGLTileSource.h
@@ -184,9 +184,9 @@ typedef NS_ENUM(NSUInteger, MGLDEMEncoding) {
Mapbox-hosted tile set, view it in
<a href="https://www.mapbox.com/studio/tilesets/">Mapbox Studio’s Tilesets editor</a>.
- Create instances of `MGLRasterSource` and `MGLVectorSource` in order to use
- `MGLTileSource`'s properties and methods. Do not create instances of `MGLTileSource`
- directly, and do not create your own subclasses of this class.
+ Create instances of `MGLRasterTileSource` and `MGLVectorTileSource` in order
+ to use `MGLTileSource`'s properties and methods. Do not create instances of
+ `MGLTileSource` directly, and do not create your own subclasses of this class.
*/
MGL_EXPORT
@interface MGLTileSource : MGLSource
diff --git a/platform/darwin/src/MGLTileSource.mm b/platform/darwin/src/MGLTileSource.mm
index c37812ab8e..87ac5be9c2 100644
--- a/platform/darwin/src/MGLTileSource.mm
+++ b/platform/darwin/src/MGLTileSource.mm
@@ -2,6 +2,7 @@
#import "MGLAttributionInfo_Private.h"
#import "MGLGeometry_Private.h"
+#import "MGLRasterDEMSource.h"
#import "NSString+MGLAdditions.h"
#import "NSValue+MGLAdditions.h"
diff --git a/platform/darwin/src/MGLVectorStyleLayer.h b/platform/darwin/src/MGLVectorStyleLayer.h
index 177b1b70f0..d9431215a1 100644
--- a/platform/darwin/src/MGLVectorStyleLayer.h
+++ b/platform/darwin/src/MGLVectorStyleLayer.h
@@ -7,7 +7,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
`MGLVectorStyleLayer` is an abstract superclass for style layers whose content
- is defined by an `MGLShapeSource` or `MGLVectorSource` object.
+ is defined by an `MGLShapeSource` or `MGLVectorTileSource` object.
Create instances of `MGLCircleStyleLayer`, `MGLFillStyleLayer`,
`MGLFillExtrusionStyleLayer`, `MGLHeatmapStyleLayer`, `MGLLineStyleLayer`, and
@@ -47,7 +47,7 @@ MGL_EXPORT
```swift
let layer = MGLLineStyleLayer(identifier: "contour", source: terrain)
layer.sourceLayerIdentifier = "contours"
- layer.predicate = NSPredicate(format: "(index == 5 || index == 10) && ele >= 1500.0")
+ layer.predicate = NSPredicate(format: "(index == 5 || index == 10) && CAST(ele, 'NSNumber') >= 1500.0")
mapView.style?.addLayer(layer)
```
*/
diff --git a/platform/darwin/src/MGLVectorSource.h b/platform/darwin/src/MGLVectorTileSource.h
index 968be3c0e0..790c9d4d42 100644
--- a/platform/darwin/src/MGLVectorSource.h
+++ b/platform/darwin/src/MGLVectorTileSource.h
@@ -5,29 +5,37 @@
NS_ASSUME_NONNULL_BEGIN
/**
- `MGLVectorSource` is a map content source that supplies tiled vector data in
- <a href="https://www.mapbox.com/vector-tiles/">Mapbox Vector Tile</a> format to
- be shown on the map. The location of and metadata about the tiles are defined
- either by an option dictionary or by an external file that conforms to the
+ `MGLVectorTileSource` is a map content source that supplies tiled vector data
+ in <a href="https://www.mapbox.com/vector-tiles/">Mapbox Vector Tile</a> format
+ to be shown on the map. The location of and metadata about the tiles are
+ defined either by an option dictionary or by an external file that conforms to
+ the
<a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>.
- A vector source is added to an `MGLStyle` object along with one or more
+ A vector tile source is added to an `MGLStyle` object along with one or more
`MGLVectorStyleLayer` objects. A vector style layer defines the appearance of
- any content supplied by the vector source.
+ any content supplied by the vector tile source.
+
+ `MGLVectorTileSource` is optimized for data sets that are too large to fit
+ completely in memory, such as vector tile sets or data sets managed in
+ <a href="https://www.mapbox.com/studio/">Mapbox Studio</a>. For
+ <a href="http://geojson.org/">GeoJSON</a> data, use the `MGLShapeSource`
+ class. For tiled data that changes dynamically, the `MGLComputedShapeSource`
+ class may be a suitable alternative.
Each
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-vector"><code>vector</code></a>
source defined by the style JSON file is represented at runtime by an
- `MGLVectorSource` object that you can use to initialize new style layers. You
- can also add and remove sources dynamically using methods such as
+ `MGLVectorTileSource` 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:]`.
Within each vector tile, each geometric coordinate must lie between
−1&nbsp;×&nbsp;<var>extent</var> and
(<var>extent</var>&nbsp;×&nbsp;2)&nbsp;−&nbsp;1, inclusive. Any vector style
- layer initialized with a vector source must have a non-`nil` value in its
+ layer initialized with a vector tile source must have a non-`nil` value in its
`sourceLayerIdentifier` property.
- Commonly used vector sources include
+ Commonly used vector tile sources include
<a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets</a>,
<a href="https://www.mapbox.com/vector-tiles/mapbox-terrain/">Mapbox Terrain</a>,
and
@@ -36,23 +44,24 @@ NS_ASSUME_NONNULL_BEGIN
### Example
```swift
- let source = MGLVectorSource(identifier: "pois", tileURLTemplates: ["https://example.com/vector-tiles/{z}/{x}/{y}.mvt"], options: [
+ let source = MGLVectorTileSource(identifier: "pois", tileURLTemplates: ["https://example.com/vector-tiles/{z}/{x}/{y}.mvt"], options: [
.minimumZoomLevel: 9,
.maximumZoomLevel: 16,
.attributionInfos: [
- MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "http://mapbox.com"))
+ MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "https://mapbox.com"))
]
])
mapView.style?.addSource(source)
```
*/
MGL_EXPORT
-@interface MGLVectorSource : MGLTileSource
+@interface MGLVectorTileSource : MGLTileSource
#pragma mark Initializing a Source
/**
- Returns a vector source initialized with an identifier and configuration URL.
+ Returns a vector tile source initialized with an identifier and configuration
+ URL.
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
@@ -66,12 +75,12 @@ MGL_EXPORT
which it is added.
@param configurationURL A URL to a TileJSON configuration file describing the
source’s contents and other metadata.
- @return An initialized vector source.
+ @return An initialized vector tile source.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL NS_DESIGNATED_INITIALIZER;
/**
- Returns a vector source initialized an identifier, tile URL templates, and
+ Returns a vector tile source initialized an identifier, tile URL templates, and
options.
Tile URL templates are strings that specify the URLs of the vector tiles to
diff --git a/platform/darwin/src/MGLVectorSource.mm b/platform/darwin/src/MGLVectorTileSource.mm
index 90ffe6f98b..c1f7267e4a 100644
--- a/platform/darwin/src/MGLVectorSource.mm
+++ b/platform/darwin/src/MGLVectorTileSource.mm
@@ -1,4 +1,4 @@
-#import "MGLVectorSource_Private.h"
+#import "MGLVectorTileSource_Private.h"
#import "MGLFeature_Private.h"
#import "MGLSource_Private.h"
@@ -13,13 +13,13 @@
#include <mbgl/style/sources/vector_source.hpp>
#include <mbgl/renderer/renderer.hpp>
-@interface MGLVectorSource ()
+@interface MGLVectorTileSource ()
@property (nonatomic, readonly) mbgl::style::VectorSource *rawSource;
@end
-@implementation MGLVectorSource
+@implementation MGLVectorTileSource
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL {
auto source = std::make_unique<mbgl::style::VectorSource>(identifier.UTF8String,
@@ -73,30 +73,57 @@
@end
-@implementation MGLVectorSource (Private)
+@implementation MGLVectorTileSource (Private)
+
+/**
+ An array of locale codes with dedicated name fields in the Mapbox Streets
+ source.
+
+ https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview
+ */
+static NSArray * const MGLMapboxStreetsLanguages = @[
+ @"ar", @"de", @"en", @"es", @"fr", @"pt", @"ru", @"zh", @"zh-Hans",
+];
+
+/**
+ Like `MGLMapboxStreetsLanguages`, but deanglicized for use with
+ `+[NSBundle preferredLocalizationsFromArray:forPreferences:]`.
+ */
+static NSArray * const MGLMapboxStreetsAlternativeLanguages = @[
+ @"mul", @"ar", @"de", @"es", @"fr", @"pt", @"ru", @"zh", @"zh-Hans",
+];
+ (NS_SET_OF(NSString *) *)mapboxStreetsLanguages {
- // https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview
static dispatch_once_t onceToken;
static NS_SET_OF(NSString *) *mapboxStreetsLanguages;
dispatch_once(&onceToken, ^{
- // https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview
- mapboxStreetsLanguages = [NSSet setWithObjects:@"ar", @"de", @"en", @"es", @"fr", @"pt", @"ru", @"zh", @"zh-Hans", nil];
+ mapboxStreetsLanguages = [NSSet setWithArray:MGLMapboxStreetsLanguages];
});
return mapboxStreetsLanguages;
}
+ (NSString *)preferredMapboxStreetsLanguage {
- NSArray<NSString *> *supportedLanguages = [MGLVectorSource mapboxStreetsLanguages].allObjects;
- NSArray<NSString *> *preferredLanguages = [NSBundle preferredLocalizationsFromArray:supportedLanguages
- forPreferences:[NSLocale preferredLanguages]];
+ return [self preferredMapboxStreetsLanguageForPreferences:[NSLocale preferredLanguages]];
+}
+
++ (NSString *)preferredMapboxStreetsLanguageForPreferences:(NSArray<NSString *> *)preferencesArray {
+ BOOL acceptsEnglish = [preferencesArray filteredArrayUsingPredicate:
+ [NSPredicate predicateWithBlock:^BOOL(NSString * _Nullable language, NSDictionary<NSString *,id> * _Nullable bindings) {
+ return [[NSLocale localeWithLocaleIdentifier:language].languageCode isEqualToString:@"en"];
+ }]].count;
+
+ NSArray<NSString *> *preferredLanguages = [NSBundle preferredLocalizationsFromArray:MGLMapboxStreetsAlternativeLanguages
+ forPreferences:preferencesArray];
NSString *mostSpecificLanguage;
for (NSString *language in preferredLanguages) {
if (language.length > mostSpecificLanguage.length) {
mostSpecificLanguage = language;
}
}
- return mostSpecificLanguage ?: @"en";
+ if ([mostSpecificLanguage isEqualToString:@"mul"]) {
+ return acceptsEnglish ? @"en" : nil;
+ }
+ return mostSpecificLanguage;
}
- (BOOL)isMapboxStreets {
@@ -116,7 +143,7 @@
// Replace {name} and {name_*} with the matching localized name tag.
NSString *localizedKey = preferredLanguage ? [NSString stringWithFormat:@"name_%@", preferredLanguage] : @"name";
NSMutableDictionary *localizedKeysByKey = [NSMutableDictionary dictionaryWithObject:localizedKey forKey:@"name"];
- for (NSString *languageCode in [MGLVectorSource mapboxStreetsLanguages]) {
+ for (NSString *languageCode in [MGLVectorTileSource mapboxStreetsLanguages]) {
NSString *key = [NSString stringWithFormat:@"name_%@", languageCode];
localizedKeysByKey[key] = localizedKey;
}
diff --git a/platform/darwin/src/MGLVectorSource_Private.h b/platform/darwin/src/MGLVectorTileSource_Private.h
index 7d19e03a99..77521869f1 100644
--- a/platform/darwin/src/MGLVectorSource_Private.h
+++ b/platform/darwin/src/MGLVectorTileSource_Private.h
@@ -1,14 +1,15 @@
-#import "MGLVectorSource.h"
+#import "MGLVectorTileSource.h"
NS_ASSUME_NONNULL_BEGIN
-@interface MGLVectorSource (Private)
+@interface MGLVectorTileSource (Private)
@property (nonatomic, readonly, getter=isMapboxStreets) BOOL mapboxStreets;
+ (NS_SET_OF(NSString *) *)mapboxStreetsLanguages;
-+ (NSString *)preferredMapboxStreetsLanguage;
++ (nullable NSString *)preferredMapboxStreetsLanguage;
++ (nullable NSString *)preferredMapboxStreetsLanguageForPreferences:(NSArray<NSString *> *)preferencesArray;
- (NS_DICTIONARY_OF(NSString *, NSString *) *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage;
diff --git a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
index 5b54d66aeb..380215ff32 100644
--- a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
+++ b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
@@ -1,231 +1,12 @@
#import "NSComparisonPredicate+MGLAdditions.h"
+#import "MGLStyleValue_Private.h"
+
#import "NSPredicate+MGLAdditions.h"
#import "NSExpression+MGLPrivateAdditions.h"
@implementation NSComparisonPredicate (MGLAdditions)
-- (mbgl::style::Filter)mgl_filter {
- NSExpression *leftExpression = self.leftExpression;
- NSExpression *rightExpression = self.rightExpression;
- NSExpressionType leftType = leftExpression.expressionType;
- NSExpressionType rightType = rightExpression.expressionType;
- BOOL isReversed = ((leftType == NSConstantValueExpressionType || leftType == NSAggregateExpressionType)
- && rightType == NSKeyPathExpressionType);
- switch (self.predicateOperatorType) {
- case NSEqualToPredicateOperatorType: {
- mbgl::style::EqualsFilter eqFilter;
- eqFilter.key = self.mgl_keyPath.UTF8String;
- eqFilter.value = self.mgl_constantValue;
-
- // Convert $type == to TypeEqualsFilter.
- if (eqFilter.key == "$type") {
- mbgl::style::TypeEqualsFilter typeEqFilter;
- typeEqFilter.value = self.mgl_featureType;
- return typeEqFilter;
- }
-
- // Convert $id == to IdentifierEqualsFilter.
- if (eqFilter.key == "$id") {
- // Convert $id == nil to NotHasIdentifierFilter.
- if (eqFilter.value.is<mbgl::NullValue>()) {
- return mbgl::style::NotHasIdentifierFilter();
- }
-
- mbgl::style::IdentifierEqualsFilter idEqFilter;
- idEqFilter.value = self.mgl_featureIdentifier;
- return idEqFilter;
- }
-
- // Convert == nil to NotHasFilter.
- if (eqFilter.value.is<mbgl::NullValue>()) {
- mbgl::style::NotHasFilter notHasFilter;
- notHasFilter.key = eqFilter.key;
- return notHasFilter;
- }
-
- return eqFilter;
- }
- case NSNotEqualToPredicateOperatorType: {
- mbgl::style::NotEqualsFilter neFilter;
- neFilter.key = self.mgl_keyPath.UTF8String;
- neFilter.value = self.mgl_constantValue;
-
- // Convert $type != to TypeNotEqualsFilter.
- if (neFilter.key == "$type") {
- mbgl::style::TypeNotEqualsFilter typeNeFilter;
- typeNeFilter.value = self.mgl_featureType;
- return typeNeFilter;
- }
-
- // Convert $id != to IdentifierNotEqualsFilter.
- if (neFilter.key == "$id") {
- // Convert $id != nil to HasIdentifierFilter.
- if (neFilter.value.is<mbgl::NullValue>()) {
- return mbgl::style::HasIdentifierFilter();
- }
-
- mbgl::style::IdentifierNotEqualsFilter idNeFilter;
- idNeFilter.value = self.mgl_featureIdentifier;
- return idNeFilter;
- }
-
- // Convert != nil to HasFilter.
- if (neFilter.value.is<mbgl::NullValue>()) {
- mbgl::style::HasFilter hasFilter;
- hasFilter.key = neFilter.key;
- return hasFilter;
- }
-
- return neFilter;
- }
- case NSGreaterThanPredicateOperatorType: {
- if (isReversed) {
- mbgl::style::LessThanFilter ltFilter;
- ltFilter.key = self.mgl_keyPath.UTF8String;
- ltFilter.value = self.mgl_constantValue;
- return ltFilter;
- } else {
- mbgl::style::GreaterThanFilter gtFilter;
- gtFilter.key = self.mgl_keyPath.UTF8String;
- gtFilter.value = self.mgl_constantValue;
- return gtFilter;
- }
- }
- case NSGreaterThanOrEqualToPredicateOperatorType: {
- if (isReversed) {
- mbgl::style::LessThanEqualsFilter lteFilter;
- lteFilter.key = self.mgl_keyPath.UTF8String;
- lteFilter.value = self.mgl_constantValue;
- return lteFilter;
- } else {
- mbgl::style::GreaterThanEqualsFilter gteFilter;
- gteFilter.key = self.mgl_keyPath.UTF8String;
- gteFilter.value = self.mgl_constantValue;
- return gteFilter;
- }
- }
- case NSLessThanPredicateOperatorType: {
- if (isReversed) {
- mbgl::style::GreaterThanFilter gtFilter;
- gtFilter.key = self.mgl_keyPath.UTF8String;
- gtFilter.value = self.mgl_constantValue;
- return gtFilter;
- } else {
- mbgl::style::LessThanFilter ltFilter;
- ltFilter.key = self.mgl_keyPath.UTF8String;
- ltFilter.value = self.mgl_constantValue;
- return ltFilter;
- }
- }
- case NSLessThanOrEqualToPredicateOperatorType: {
- if (isReversed) {
- mbgl::style::GreaterThanEqualsFilter gteFilter;
- gteFilter.key = self.mgl_keyPath.UTF8String;
- gteFilter.value = self.mgl_constantValue;
- return gteFilter;
- } else {
- mbgl::style::LessThanEqualsFilter lteFilter;
- lteFilter.key = self.mgl_keyPath.UTF8String;
- lteFilter.value = self.mgl_constantValue;
- return lteFilter;
- }
- }
- case NSInPredicateOperatorType: {
- if (isReversed) {
- if (leftType == NSConstantValueExpressionType && [leftExpression.constantValue isKindOfClass:[NSString class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"CONTAINS not supported for string comparison."];
- }
- [NSException raise:NSInvalidArgumentException
- format:@"Predicate cannot compare values IN attribute."];
- }
-
- // Convert $type IN to TypeInFilter.
- if ([leftExpression.keyPath isEqualToString:@"$type"]) {
- mbgl::style::TypeInFilter typeInFilter;
- typeInFilter.values = rightExpression.mgl_aggregateFeatureType;
- return typeInFilter;
- }
-
- // Convert $id IN to IdentifierInFilter.
- if ([leftExpression.keyPath isEqualToString:@"$id"]) {
- mbgl::style::IdentifierInFilter idInFilter;
- idInFilter.values = rightExpression.mgl_aggregateFeatureIdentifier;
- return idInFilter;
- }
-
- mbgl::style::InFilter inFilter;
- inFilter.key = leftExpression.keyPath.UTF8String;
- inFilter.values = rightExpression.mgl_aggregateMBGLValue;
- return inFilter;
- }
- case NSContainsPredicateOperatorType: {
- if (!isReversed) {
- if (rightType == NSConstantValueExpressionType && [rightExpression.constantValue isKindOfClass:[NSString class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"IN not supported for string comparison."];
- }
- [NSException raise:NSInvalidArgumentException
- format:@"Predicate cannot compare attribute CONTAINS values."];
- }
-
- // Convert CONTAINS $type to TypeInFilter.
- if ([rightExpression.keyPath isEqualToString:@"$type"]) {
- mbgl::style::TypeInFilter typeInFilter;
- typeInFilter.values = leftExpression.mgl_aggregateFeatureType;
- return typeInFilter;
- }
-
- // Convert CONTAINS $id to IdentifierInFilter.
- if ([rightExpression.keyPath isEqualToString:@"$id"]) {
- mbgl::style::IdentifierInFilter idInFilter;
- idInFilter.values = leftExpression.mgl_aggregateFeatureIdentifier;
- return idInFilter;
- }
-
- mbgl::style::InFilter inFilter;
- inFilter.key = rightExpression.keyPath.UTF8String;
- inFilter.values = leftExpression.mgl_aggregateMBGLValue;
- return inFilter;
- }
- case NSBetweenPredicateOperatorType: {
- if (isReversed) {
- [NSException raise:NSInvalidArgumentException
- format:@"Predicate cannot compare bounds BETWEEN attribute."];
- }
- if (![rightExpression.constantValue isKindOfClass:[NSArray class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"Right side of BETWEEN predicate must be an array."]; // not NSSet
- }
- auto values = rightExpression.mgl_aggregateMBGLValue;
- if (values.size() != 2) {
- [NSException raise:NSInvalidArgumentException
- format:@"Right side of BETWEEN predicate must have two items."];
- }
- mbgl::style::AllFilter allFilter;
- mbgl::style::GreaterThanEqualsFilter gteFilter;
- gteFilter.key = leftExpression.keyPath.UTF8String;
- gteFilter.value = values[0];
- allFilter.filters.push_back(gteFilter);
- mbgl::style::LessThanEqualsFilter lteFilter;
- lteFilter.key = leftExpression.keyPath.UTF8String;
- lteFilter.value = values[1];
- allFilter.filters.push_back(lteFilter);
- return allFilter;
- }
- case NSMatchesPredicateOperatorType:
- case NSLikePredicateOperatorType:
- case NSBeginsWithPredicateOperatorType:
- case NSEndsWithPredicateOperatorType:
- case NSCustomSelectorPredicateOperatorType:
- [NSException raise:NSInvalidArgumentException
- format:@"NSPredicateOperatorType:%lu is not supported.", (unsigned long)self.predicateOperatorType];
- }
-
- return {};
-}
-
- (NSString *)mgl_keyPath {
NSExpression *leftExpression = self.leftExpression;
NSExpression *rightExpression = self.rightExpression;
@@ -318,14 +99,45 @@
case NSNotEqualToPredicateOperatorType:
op = @"!=";
break;
+ case NSBetweenPredicateOperatorType: {
+ op = @"all";
+ NSArray *limits = self.rightExpression.constantValue;
+ NSPredicate *leftHandPredicate = [NSComparisonPredicate predicateWithLeftExpression:limits[0]
+ rightExpression:self.leftExpression
+ modifier:NSDirectPredicateModifier
+ type:NSLessThanOrEqualToPredicateOperatorType
+ options:0];
+ NSPredicate *rightHandPredicate = [NSComparisonPredicate predicateWithLeftExpression:self.leftExpression
+ rightExpression:limits[1]
+ modifier:NSDirectPredicateModifier
+ type:NSLessThanOrEqualToPredicateOperatorType
+ options:0];
+ return @[op, leftHandPredicate.mgl_jsonExpressionObject, rightHandPredicate.mgl_jsonExpressionObject];
+ }
+ case NSInPredicateOperatorType: {
+ NSMutableArray *elements = [NSMutableArray arrayWithObjects:@"match", self.leftExpression.mgl_jsonExpressionObject, nil];
+ NSArray *optionsExpressions = self.rightExpression.constantValue;
+ for (id object in optionsExpressions) {
+ id option = ((NSExpression *)object).mgl_jsonExpressionObject;
+ [elements addObject:option];
+ [elements addObject:@YES];
+ }
+ [elements addObject:@NO];
+ return elements;
+ }
+ case NSContainsPredicateOperatorType: {
+ NSPredicate *inPredicate = [NSComparisonPredicate predicateWithLeftExpression:self.rightExpression
+ rightExpression:self.leftExpression
+ modifier:self.comparisonPredicateModifier
+ type:NSInPredicateOperatorType
+ options:self.options];
+ return inPredicate.mgl_jsonExpressionObject;
+ }
case NSMatchesPredicateOperatorType:
case NSLikePredicateOperatorType:
case NSBeginsWithPredicateOperatorType:
case NSEndsWithPredicateOperatorType:
- case NSInPredicateOperatorType:
case NSCustomSelectorPredicateOperatorType:
- case NSContainsPredicateOperatorType:
- case NSBetweenPredicateOperatorType:
[NSException raise:NSInvalidArgumentException
format:@"NSPredicateOperatorType:%lu is not supported.", (unsigned long)self.predicateOperatorType];
}
diff --git a/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm b/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm
index 19568b8033..5a98b763ea 100644
--- a/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm
+++ b/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm
@@ -1,8 +1,12 @@
#import "NSCompoundPredicate+MGLAdditions.h"
+#import "MGLStyleValue_Private.h"
+
#import "NSPredicate+MGLAdditions.h"
#import "NSExpression+MGLPrivateAdditions.h"
+#include <mbgl/style/conversion/property_value.hpp>
+
@implementation NSCompoundPredicate (MGLAdditions)
- (std::vector<mbgl::style::Filter>)mgl_subfilters
@@ -14,62 +18,6 @@
return filters;
}
-- (mbgl::style::Filter)mgl_filter
-{
- switch (self.compoundPredicateType) {
- case NSNotPredicateType: {
- NSAssert(self.subpredicates.count <= 1, @"NOT predicate cannot have multiple subpredicates.");
- NSPredicate *subpredicate = self.subpredicates.firstObject;
- mbgl::style::Filter subfilter = subpredicate.mgl_filter;
-
- // Convert NOT(!= nil) to NotHasFilter.
- if (subfilter.is<mbgl::style::HasFilter>()) {
- auto hasFilter = subfilter.get<mbgl::style::HasFilter>();
- return mbgl::style::NotHasFilter { .key = hasFilter.key };
- }
-
- // Convert NOT(== nil) to HasFilter.
- if (subfilter.is<mbgl::style::NotHasFilter>()) {
- auto hasFilter = subfilter.get<mbgl::style::NotHasFilter>();
- return mbgl::style::HasFilter { .key = hasFilter.key };
- }
-
- // Convert NOT(IN) or NOT(CONTAINS) to NotInFilter.
- if (subfilter.is<mbgl::style::InFilter>()) {
- auto inFilter = subfilter.get<mbgl::style::InFilter>();
- mbgl::style::NotInFilter notInFilter;
- notInFilter.key = inFilter.key;
- notInFilter.values = inFilter.values;
- return notInFilter;
- }
-
- // Convert NOT(), NOT(AND), NOT(NOT), NOT(==), etc. into NoneFilter.
- mbgl::style::NoneFilter noneFilter;
- if (subfilter.is<mbgl::style::AnyFilter>()) {
- // Flatten NOT(OR).
- noneFilter.filters = subfilter.get<mbgl::style::AnyFilter>().filters;
- } else if (subpredicate) {
- noneFilter.filters = { subfilter };
- }
- return noneFilter;
- }
- case NSAndPredicateType: {
- mbgl::style::AllFilter filter;
- filter.filters = self.mgl_subfilters;
- return filter;
- }
- case NSOrPredicateType: {
- mbgl::style::AnyFilter filter;
- filter.filters = self.mgl_subfilters;
- return filter;
- }
- }
-
- [NSException raise:@"Compound predicate type not handled"
- format:@""];
- return {};
-}
-
@end
@implementation NSCompoundPredicate (MGLExpressionAdditions)
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.h b/platform/darwin/src/NSExpression+MGLAdditions.h
index b4d36bc1b1..cfdf27aade 100644
--- a/platform/darwin/src/NSExpression+MGLAdditions.h
+++ b/platform/darwin/src/NSExpression+MGLAdditions.h
@@ -9,15 +9,150 @@
NS_ASSUME_NONNULL_BEGIN
+typedef NSString *MGLExpressionInterpolationMode NS_TYPED_ENUM;
+
+/**
+ An `NSString` identifying the `linear` interpolation type in an `NSExpression`.
+
+ This attribute corresponds to the `linear` value in the
+ <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-interpolate"><code>interpolate</code></a>
+ expression operator in the Mapbox Style Specification.
+ */
+extern MGL_EXPORT const MGLExpressionInterpolationMode MGLExpressionInterpolationModeLinear;
+
+/**
+ An `NSString` identifying the `expotential` interpolation type in an `NSExpression`.
+
+ This attribute corresponds to the `exponential` value in the
+ <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-interpolate"><code>interpolate</code></a>
+ expression operator in the Mapbox Style Specification.
+ */
+extern MGL_EXPORT const MGLExpressionInterpolationMode MGLExpressionInterpolationModeExponential;
+
+/**
+ An `NSString` identifying the `cubic-bezier` interpolation type in an `NSExpression`.
+
+ This attribute corresponds to the `cubic-bezier` value in the
+ <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-interpolate"><code>interpolate</code></a>
+ expression operator in the Mapbox Style Specification.
+ */
+extern MGL_EXPORT const MGLExpressionInterpolationMode MGLExpressionInterpolationModeCubicBezier;
+
+/**
+ Methods for creating expressions that use Mapbox-specific functionality and for
+ converting to and from the JSON format defined in the
+ <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions">Mapbox Style Specification</a>.
+ */
@interface NSExpression (MGLAdditions)
+#pragma mark Creating Variable Expressions
+
+/**
+ `NSExpression` variable that corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-zoom"><code>zoom</code></a>
+ expression operator in the Mapbox Style Specification.
+ */
+@property (class, nonatomic, readonly) NSExpression *zoomLevelVariableExpression;
+
+/**
+ `NSExpression` variable that corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-heatmap-density"><code>heatmap-density</code></a>
+ expression operator in the Mapbox Style Specification.
+ */
+@property (class, nonatomic, readonly) NSExpression *heatmapDensityVariableExpression;
+
+/**
+ `NSExpression` variable that corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#eexpressions-geometry-type"><code>geometry-type</code></a>
+ expression operator in the Mapbox Style Specification.
+ */
+@property (class, nonatomic, readonly) NSExpression *geometryTypeVariableExpression;
+
+/**
+ `NSExpression` variable that corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-id"><code>id</code></a>
+ expression operator in the Mapbox Style Specification.
+ */
+@property (class, nonatomic, readonly) NSExpression *featureIdentifierVariableExpression;
+
+/**
+ `NSExpression` variable that corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-properties"><code>properties</code></a>
+ expression operator in the Mapbox Style Specification.
+ */
+@property (class, nonatomic, readonly) NSExpression *featureAttributesVariableExpression;
+
+@property (class, nonatomic, readonly) NSExpression *featurePropertiesVariableExpression __attribute__((deprecated("Use -featureAttributesVariableExpression.")));
+
+#pragma mark Creating Conditional Expressions
+
+/**
+ Returns a conditional function expression specifying the string predicate, and
+ expressions for each condition.
+
+ @param conditionPredicate The predicate to get evaluated.
+ @param trueExpression The expression for conditions equal to true.
+ @param falseExpression The expression for conditions equal to false.
+ */
++ (instancetype)mgl_expressionForConditional:(nonnull NSPredicate *)conditionPredicate trueExpression:(nonnull NSExpression *)trueExpression falseExpresssion:(nonnull NSExpression *)falseExpression NS_SWIFT_NAME(init(forMGLConditional:trueExpression:falseExpression:));
+
+#pragma mark Creating Ramp, Scale, and Curve Expressions
+
+/**
+ Returns a step function expression specifying the stepping, from expression
+ and stops.
+
+ @param steppingExpression The stepping expression.
+ @param minimumExpression The expression which could be a constant or function expression.
+ @param stops The stops must be an `NSDictionary` constant `NSExpression`.
+ */
++ (instancetype)mgl_expressionForSteppingExpression:(nonnull NSExpression*)steppingExpression fromExpression:(nonnull NSExpression *)minimumExpression stops:(nonnull NSExpression*)stops NS_SWIFT_NAME(init(forMGLStepping:from:stops:));
+
+/**
+ Returns an interpolated function expression specifying the function operator, curve type,
+ parameters and steps.
+
+ @param inputExpression The interpolating expression input.
+ @param curveType The curve type could be `MGLExpressionInterpolationModeLinear`,
+ `MGLExpressionInterpolationModeExponential` and
+ `MGLExpressionInterpolationModeCubicBezier`.
+ @param parameters The parameters expression.
+ @param stops The stops expression.
+ */
++ (instancetype)mgl_expressionForInterpolatingExpression:(nonnull NSExpression*)inputExpression withCurveType:(nonnull MGLExpressionInterpolationMode)curveType parameters:(nullable NSExpression *)parameters stops:(nonnull NSExpression*)stops NS_SWIFT_NAME(init(forMGLInterpolating:curveType:parameters:stops:));
+
+/**
+ Returns a match function expression specifying the input, matching values,
+ and default value.
+
+ @param inputExpression The matching expression.
+ @param matchedExpressions The matched values expression dictionary must be condition : value.
+ @param defaultExpression The defaultValue expression to be used in case there is no match.
+ */
++ (instancetype)mgl_expressionForMatchingExpression:(nonnull NSExpression *)inputExpression inDictionary:(nonnull NSDictionary<NSExpression *, NSExpression *> *)matchedExpressions defaultExpression:(nonnull NSExpression *)defaultExpression NS_SWIFT_NAME(init(forMGLMatchingKey:in:default:));
+
+#pragma mark Concatenating String Expressions
+
+/**
+ Returns a constant expression appending the passed expression.
+
+ @note Both the receiver and the given expression must be an `NSString` constant
+ expression type; otherwise, an exception is rised.
+
+ @param expression The expression to append to the receiver.
+ */
+- (instancetype)mgl_expressionByAppendingExpression:(nonnull NSExpression *)expression NS_SWIFT_NAME(mgl_appending(_:));
+
+#pragma mark Converting JSON Expressions
+
/**
Returns an expression equivalent to the given Foundation object deserialized
from JSON data.
The Foundation object is interpreted according to the
[Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions).
- See the “[Predicates and Expressions](../predicates-and-expressions.html)”
+ See the
+ “[Information for Style Authors](../for-style-authors.html#setting-attribute-values)”
guide for a correspondence of operators and types between the style
specification and the `NSExpression` representation used by this SDK.
@@ -26,14 +161,15 @@ NS_ASSUME_NONNULL_BEGIN
@return An initialized expression equivalent to `object`, suitable for use as
the value of a style layer attribute.
*/
-+ (instancetype)mgl_expressionWithJSONObject:(id)object;
++ (instancetype)expressionWithMGLJSONObject:(id)object NS_SWIFT_NAME(init(mglJSONObject:));
/**
An equivalent Foundation object that can be serialized as JSON.
The Foundation object conforms to the
[Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions).
- See the “[Predicates and Expressions](../predicates-and-expressions.html)”
+ See the
+ “[Information for Style Authors](../for-style-authors.html#setting-attribute-values)”
guide for a correspondence of operators and types between the style
specification and the `NSExpression` representation used by this SDK.
@@ -42,6 +178,24 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic, readonly) id mgl_jsonExpressionObject;
+#pragma mark Localizing the Expression
+
+/**
+ Returns a copy of the receiver localized into the given locale.
+
+ This method assumes the receiver refers to the feature attributes that are
+ available in vector tiles supplied by the
+ <a href="https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview">Mapbox Streets source</a>.
+ On iOS, the user can set the system’s preferred language in Settings, General
+ Settings, Language & Region. On macOS, the user can set the system’s preferred
+ language in the Language & Region pane of System Preferences.
+
+ @param locale The locale into which labels should be localized. To use the
+ system’s preferred language, if supported, specify `nil`. To use the local
+ language, specify a locale with the identifier `mul`.
+ */
+- (NSExpression *)mgl_expressionLocalizedIntoLocale:(nullable NSLocale *)locale;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm
index 5ad565c398..c82a7dc008 100644
--- a/platform/darwin/src/NSExpression+MGLAdditions.mm
+++ b/platform/darwin/src/NSExpression+MGLAdditions.mm
@@ -10,9 +10,239 @@
#endif
#import "NSPredicate+MGLAdditions.h"
#import "NSValue+MGLStyleAttributeAdditions.h"
+#import "MGLVectorTileSource_Private.h"
+
+#import <objc/runtime.h>
#import <mbgl/style/expression/expression.hpp>
+const MGLExpressionInterpolationMode MGLExpressionInterpolationModeLinear = @"linear";
+const MGLExpressionInterpolationMode MGLExpressionInterpolationModeExponential = @"exponential";
+const MGLExpressionInterpolationMode MGLExpressionInterpolationModeCubicBezier = @"cubic-bezier";
+
+@interface MGLAftermarketExpressionInstaller: NSObject
+@end
+
+@implementation MGLAftermarketExpressionInstaller
+
++ (void)load {
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ [self installFunctions];
+ });
+}
+
+/**
+ Adds to NSExpression’s built-in repertoire of functions.
+ */
++ (void)installFunctions {
+ Class MGLAftermarketExpressionInstaller = [self class];
+
+ // NSExpression’s built-in functions are backed by class methods on a
+ // private class, so use a function expression to get at the class.
+ // http://funwithobjc.tumblr.com/post/2922267976/using-custom-functions-with-nsexpression
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"sum({})"];
+ NSString *className = NSStringFromClass([functionExpression.operand.constantValue class]);
+
+ // Effectively categorize the class with some extra class methods.
+ Class NSPredicateUtilities = objc_getMetaClass(className.UTF8String);
+#pragma clang push
+#pragma clang diagnostic ignored "-Wundeclared-selector"
+ #define INSTALL_METHOD(sel) \
+ { \
+ Method method = class_getInstanceMethod(MGLAftermarketExpressionInstaller, @selector(sel)); \
+ class_addMethod(NSPredicateUtilities, @selector(sel), method_getImplementation(method), method_getTypeEncoding(method)); \
+ }
+ #define INSTALL_CONTROL_STRUCTURE(sel) \
+ { \
+ Method method = class_getInstanceMethod(MGLAftermarketExpressionInstaller, @selector(sel:)); \
+ class_addMethod(NSPredicateUtilities, @selector(sel), method_getImplementation(method), method_getTypeEncoding(method)); \
+ class_addMethod(NSPredicateUtilities, @selector(sel:), method_getImplementation(method), method_getTypeEncoding(method)); \
+ }
+
+ // Install method-like functions, taking the number of arguments implied by
+ // the selector name.
+ INSTALL_METHOD(mgl_join:);
+ INSTALL_METHOD(mgl_round:);
+ INSTALL_METHOD(mgl_interpolate:withCurveType:parameters:stops:);
+ INSTALL_METHOD(mgl_step:from:stops:);
+ INSTALL_METHOD(mgl_coalesce:);
+ INSTALL_METHOD(mgl_does:have:);
+ INSTALL_METHOD(mgl_acos:);
+ INSTALL_METHOD(mgl_cos:);
+ INSTALL_METHOD(mgl_asin:);
+ INSTALL_METHOD(mgl_sin:);
+ INSTALL_METHOD(mgl_atan:);
+ INSTALL_METHOD(mgl_tan:);
+ INSTALL_METHOD(mgl_log2:);
+
+ // Install functions that resemble control structures, taking arbitrary
+ // numbers of arguments. Vararg aftermarket functions need to be declared
+ // with an explicit and implicit first argument.
+ INSTALL_CONTROL_STRUCTURE(MGL_LET);
+ INSTALL_CONTROL_STRUCTURE(MGL_MATCH);
+ INSTALL_CONTROL_STRUCTURE(MGL_IF);
+ INSTALL_CONTROL_STRUCTURE(MGL_FUNCTION);
+
+ #undef INSTALL_AFTERMARKET_FN
+#pragma clang pop
+}
+
+/**
+ Joins the given components into a single string by concatenating each component
+ in order.
+ */
+- (NSString *)mgl_join:(NSArray<NSString *> *)components {
+ return [components componentsJoinedByString:@""];
+}
+
+/**
+ Rounds the given number to the nearest integer. If the number is halfway
+ between two integers, this method rounds it away from zero.
+ */
+- (NSNumber *)mgl_round:(NSNumber *)number {
+ return @(round(number.doubleValue));
+}
+
+/**
+ Computes the principal value of the inverse cosine.
+ */
+- (NSNumber *)mgl_acos:(NSNumber *)number {
+ return @(acos(number.doubleValue));
+}
+
+/**
+ Computes the principal value of the cosine.
+ */
+- (NSNumber *)mgl_cos:(NSNumber *)number {
+ return @(cos(number.doubleValue));
+}
+
+/**
+ Computes the principal value of the inverse sine.
+ */
+- (NSNumber *)mgl_asin:(NSNumber *)number {
+ return @(asin(number.doubleValue));
+}
+
+/**
+ Computes the principal value of the sine.
+ */
+- (NSNumber *)mgl_sin:(NSNumber *)number {
+ return @(sin(number.doubleValue));
+}
+
+/**
+ Computes the principal value of the inverse tangent.
+ */
+- (NSNumber *)mgl_atan:(NSNumber *)number {
+ return @(atan(number.doubleValue));
+}
+
+/**
+ Computes the principal value of the tangent.
+ */
+- (NSNumber *)mgl_tan:(NSNumber *)number {
+ return @(tan(number.doubleValue));
+}
+
+/**
+ Computes the logarithm base two of the value.
+ */
+- (NSNumber *)mgl_log2:(NSNumber *)number {
+ return @(log2(number.doubleValue));
+}
+
+/**
+ A placeholder for a method that evaluates an interpolation expression.
+ */
+- (id)mgl_interpolate:(id)inputExpression withCurveType:(NSString *)curveType parameters:(NSDictionary *)params stops:(NSDictionary *)stops {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Interpolation expressions lack underlying Objective-C implementations."];
+ return nil;
+}
+
+/**
+ A placeholder for a method that evaluates a step expression.
+ */
+- (id)mgl_step:(id)inputExpression from:(id)minimumExpression stops:(NSDictionary *)stops {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Step expressions lack underlying Objective-C implementations."];
+ return nil;
+}
+
+/**
+ A placeholder for a method that evaluates a coalesce expression.
+ */
+- (id)mgl_coalesce:(NSArray<NSExpression *> *)elements {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Coalesce expressions lack underlying Objective-C implementations."];
+ return nil;
+}
+
+/**
+ Returns a Boolean value indicating whether the object has a value for the given
+ key.
+ */
+- (BOOL)mgl_does:(id)object have:(NSString *)key {
+ return [object valueForKey:key] != nil;
+}
+
+/**
+ A placeholder for a method that evaluates an expression based on an arbitrary
+ number of variable names and assigned expressions.
+ */
+- (id)MGL_LET:(NSString *)firstVariableName, ... {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Assignment expressions lack underlying Objective-C implementations."];
+ return nil;
+}
+
+/**
+ A placeholder for a method that evaluates an expression and returns the matching element.
+ */
+- (id)MGL_MATCH:(id)firstCondition, ... {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Assignment expressions lack underlying Objective-C implementations."];
+ return nil;
+}
+
+/**
+ A placeholder for a method that evaluates an expression and returns the matching element.
+ */
+- (id)MGL_IF:(id)firstCondition, ... {
+ va_list argumentList;
+ va_start(argumentList, firstCondition);
+
+ for (id eachExpression = firstCondition; eachExpression; eachExpression = va_arg(argumentList, id)) {
+ if ([eachExpression isKindOfClass:[NSComparisonPredicate class]]) {
+ id valueExpression = va_arg(argumentList, id);
+ if ([eachExpression evaluateWithObject:nil]) {
+ return valueExpression;
+ }
+ } else {
+ return eachExpression;
+ }
+ }
+ va_end(argumentList);
+
+ return nil;
+}
+
+
+/**
+ A placeholder for a catch-all method that evaluates an arbitrary number of
+ arguments as an expression according to the Mapbox Style Specification’s
+ expression language.
+ */
+- (id)MGL_FUNCTION:(id)firstArgument, ... {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Mapbox GL function expressions lack underlying Objective-C implementations."];
+ return nil;
+}
+
+@end
+
@implementation NSExpression (MGLPrivateAdditions)
- (std::vector<mbgl::Value>)mgl_aggregateMBGLValue {
@@ -159,6 +389,112 @@
return {};
}
+// Selectors of functions that can contain tokens in arguments.
+static NSArray * const MGLTokenizedFunctions = @[
+ @"mgl_interpolateWithCurveType:parameters:stops:",
+ @"mgl_interpolate:withCurveType:parameters:stops:",
+ @"mgl_stepWithMinimum:stops:",
+ @"mgl_step:from:stops:",
+];
+
+/**
+ Returns a copy of the given collection with tokens replaced by key path
+ expressions.
+
+ If no replacements take place, this method returns the original collection.
+ */
+NS_ARRAY_OF(NSExpression *) *MGLCollectionByReplacingTokensWithKeyPaths(NS_ARRAY_OF(NSExpression *) *collection) {
+ __block NSMutableArray *upgradedCollection;
+ [collection enumerateObjectsUsingBlock:^(NSExpression * _Nonnull item, NSUInteger idx, BOOL * _Nonnull stop) {
+ NSExpression *upgradedItem = item.mgl_expressionByReplacingTokensWithKeyPaths;
+ if (upgradedItem != item) {
+ if (!upgradedCollection) {
+ upgradedCollection = [collection mutableCopy];
+ }
+ upgradedCollection[idx] = upgradedItem;
+ }
+ }];
+ return upgradedCollection ?: collection;
+};
+
+/**
+ Returns a copy of the given stop dictionary with tokens replaced by key path
+ expressions.
+
+ If no replacements take place, this method returns the original stop
+ dictionary.
+ */
+NS_DICTIONARY_OF(NSNumber *, NSExpression *) *MGLStopDictionaryByReplacingTokensWithKeyPaths(NS_DICTIONARY_OF(NSNumber *, NSExpression *) *stops) {
+ __block NSMutableDictionary *upgradedStops;
+ [stops enumerateKeysAndObjectsUsingBlock:^(id _Nonnull zoomLevel, NSExpression * _Nonnull value, BOOL * _Nonnull stop) {
+ if (![value isKindOfClass:[NSExpression class]]) {
+ value = [NSExpression expressionForConstantValue:value];
+ }
+ NSExpression *upgradedValue = value.mgl_expressionByReplacingTokensWithKeyPaths;
+ if (upgradedValue != value) {
+ if (!upgradedStops) {
+ upgradedStops = [stops mutableCopy];
+ }
+ upgradedStops[zoomLevel] = upgradedValue;
+ }
+ }];
+ return upgradedStops ?: stops;
+};
+
+- (NSExpression *)mgl_expressionByReplacingTokensWithKeyPaths {
+ switch (self.expressionType) {
+ case NSConstantValueExpressionType: {
+ NSString *constantValue = self.constantValue;
+ if ([constantValue isKindOfClass:[NSString class]] &&
+ [constantValue containsString:@"{"] && [constantValue containsString:@"}"]) {
+ NSMutableArray *components = [NSMutableArray array];
+ NSScanner *scanner = [NSScanner scannerWithString:constantValue];
+ scanner.charactersToBeSkipped = nil;
+ while (!scanner.isAtEnd) {
+ NSString *string;
+ if ([scanner scanUpToString:@"{" intoString:&string]) {
+ [components addObject:[NSExpression expressionForConstantValue:string]];
+ }
+
+ NSString *token;
+ if ([scanner scanString:@"{" intoString:NULL]
+ && [scanner scanUpToString:@"}" intoString:&token]
+ && [scanner scanString:@"}" intoString:NULL]) {
+ [components addObject:[NSExpression expressionForKeyPath:token]];
+ }
+ }
+ if (components.count == 1) {
+ return components.firstObject;
+ }
+ return [NSExpression expressionForFunction:@"mgl_join:"
+ arguments:@[[NSExpression expressionForAggregate:components]]];
+ }
+ NSDictionary *stops = self.constantValue;
+ if ([stops isKindOfClass:[NSDictionary class]]) {
+ NSDictionary *localizedStops = MGLStopDictionaryByReplacingTokensWithKeyPaths(stops);
+ if (localizedStops != stops) {
+ return [NSExpression expressionForConstantValue:localizedStops];
+ }
+ }
+ return self;
+ }
+
+ case NSFunctionExpressionType: {
+ if ([MGLTokenizedFunctions containsObject:self.function]) {
+ NSArray *arguments = self.arguments;
+ NSArray *localizedArguments = MGLCollectionByReplacingTokensWithKeyPaths(arguments);
+ if (localizedArguments != arguments) {
+ return [NSExpression expressionForFunction:self.operand selectorName:self.function arguments:localizedArguments];
+ }
+ }
+ return self;
+ }
+
+ default:
+ return self;
+ }
+}
+
@end
@implementation NSObject (MGLExpressionAdditions)
@@ -258,6 +594,12 @@
return [self valueForKeyPath:@"mgl_jsonExpressionObject"];
}
+- (id)mgl_coalesce {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Coalesce expressions lack underlying Objective-C implementations."];
+ return nil;
+}
+
@end
@implementation NSDictionary (MGLExpressionAdditions)
@@ -271,6 +613,13 @@
return expressionObject;
}
+- (id)mgl_has:(id)element {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Has expressions lack underlying Objective-C implementations."];
+ return nil;
+
+}
+
@end
@implementation NSExpression (MGLExpressionAdditions)
@@ -281,23 +630,91 @@
return self;
}
+- (id)mgl_has:(id)element {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Has expressions lack underlying Objective-C implementations."];
+ return nil;
+}
+
@end
@implementation NSExpression (MGLAdditions)
++ (NSExpression *)zoomLevelVariableExpression {
+ return [NSExpression expressionForVariable:@"zoomLevel"];
+}
+
++ (NSExpression *)heatmapDensityVariableExpression {
+ return [NSExpression expressionForVariable:@"heatmapDensity"];
+}
+
++ (NSExpression *)geometryTypeVariableExpression {
+ return [NSExpression expressionForVariable:@"geometryType"];
+}
+
++ (NSExpression *)featureIdentifierVariableExpression {
+ return [NSExpression expressionForVariable:@"featureIdentifier"];
+}
+
++ (NSExpression *)featureAttributesVariableExpression {
+ return [NSExpression expressionForVariable:@"featureAttributes"];
+}
+
++ (NSExpression *)featurePropertiesVariableExpression {
+ return [self featureAttributesVariableExpression];
+}
+
++ (instancetype)mgl_expressionForConditional:(nonnull NSPredicate *)conditionPredicate trueExpression:(nonnull NSExpression *)trueExpression falseExpresssion:(nonnull NSExpression *)falseExpression {
+ if (@available(iOS 9.0, *)) {
+ return [NSExpression expressionForConditional:conditionPredicate trueExpression:trueExpression falseExpression:falseExpression];
+ } else {
+ return [NSExpression expressionForFunction:@"MGL_IF" arguments:@[[NSExpression expressionWithFormat:@"%@", conditionPredicate], trueExpression, falseExpression]];
+ }
+}
+
++ (instancetype)mgl_expressionForSteppingExpression:(nonnull NSExpression *)steppingExpression fromExpression:(nonnull NSExpression *)minimumExpression stops:(nonnull NSExpression *)stops {
+ return [NSExpression expressionForFunction:@"mgl_step:from:stops:"
+ arguments:@[steppingExpression, minimumExpression, stops]];
+}
+
++ (instancetype)mgl_expressionForInterpolatingExpression:(nonnull NSExpression *)inputExpression withCurveType:(nonnull MGLExpressionInterpolationMode)curveType parameters:(nullable NSExpression *)parameters stops:(nonnull NSExpression *)stops {
+ NSExpression *sanitizeParams = parameters ? parameters : [NSExpression expressionForConstantValue:nil];
+ return [NSExpression expressionForFunction:@"mgl_interpolate:withCurveType:parameters:stops:"
+ arguments:@[inputExpression, [NSExpression expressionForConstantValue:curveType], sanitizeParams, stops]];
+}
+
++ (instancetype)mgl_expressionForMatchingExpression:(nonnull NSExpression *)inputExpression inDictionary:(nonnull NSDictionary<NSExpression *, NSExpression *> *)matchedExpressions defaultExpression:(nonnull NSExpression *)defaultExpression {
+ NSMutableArray *optionsArray = [NSMutableArray arrayWithObjects:inputExpression, nil];
+
+ NSEnumerator *matchEnumerator = matchedExpressions.keyEnumerator;
+ while (NSExpression *key = matchEnumerator.nextObject) {
+ [optionsArray addObject:key];
+ [optionsArray addObject:[matchedExpressions objectForKey:key]];
+ }
+
+ [optionsArray addObject:defaultExpression];
+ return [NSExpression expressionForFunction:@"MGL_MATCH"
+ arguments:optionsArray];
+}
+
+- (instancetype)mgl_expressionByAppendingExpression:(nonnull NSExpression *)expression {
+ NSExpression *subexpression = [NSExpression expressionForAggregate:@[self, expression]];
+ return [NSExpression expressionForFunction:@"mgl_join:" arguments:@[subexpression]];
+}
+
static NSDictionary<NSString *, NSString *> *MGLFunctionNamesByExpressionOperator;
static NSDictionary<NSString *, NSString *> *MGLExpressionOperatorsByFunctionNames;
NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
NSMutableArray *subexpressions = [NSMutableArray arrayWithCapacity:objects.count];
for (id object in objects) {
- NSExpression *expression = [NSExpression mgl_expressionWithJSONObject:object];
+ NSExpression *expression = [NSExpression expressionWithMGLJSONObject:object];
[subexpressions addObject:expression];
}
return subexpressions;
}
-+ (instancetype)mgl_expressionWithJSONObject:(id)object {
++ (instancetype)expressionWithMGLJSONObject:(id)object {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
MGLFunctionNamesByExpressionOperator = @{
@@ -309,9 +726,21 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
@"sqrt": @"sqrt:",
@"log10": @"log:",
@"ln": @"ln:",
+ @"abs": @"abs:",
+ @"round": @"mgl_round:",
+ @"acos" : @"mgl_acos:",
+ @"cos" : @"mgl_cos:",
+ @"asin" : @"mgl_asin:",
+ @"sin" : @"mgl_sin:",
+ @"atan" : @"mgl_atan:",
+ @"tan" : @"mgl_tan:",
+ @"log2" : @"mgl_log2:",
+ @"floor": @"floor:",
+ @"ceil": @"ceiling:",
@"^": @"raise:toPower:",
@"upcase": @"uppercase:",
@"downcase": @"lowercase:",
+ @"let": @"MGL_LET",
};
});
@@ -329,7 +758,7 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
if ([object isKindOfClass:[NSDictionary class]]) {
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:[object count]];
[object enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
- dictionary[key] = [NSExpression mgl_expressionWithJSONObject:obj];
+ dictionary[key] = [NSExpression expressionWithMGLJSONObject:obj];
}];
return [NSExpression expressionForConstantValue:dictionary];
}
@@ -358,31 +787,45 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
if ([argumentObjects.firstObject isKindOfClass:[NSArray class]]) {
return [NSExpression expressionForAggregate:MGLSubexpressionsWithJSONObjects(argumentObjects.firstObject)];
}
- return [NSExpression mgl_expressionWithJSONObject:argumentObjects.firstObject];
+ return [NSExpression expressionWithMGLJSONObject:argumentObjects.firstObject];
} else if ([op isEqualToString:@"to-boolean"]) {
- NSExpression *operand = [NSExpression mgl_expressionWithJSONObject:argumentObjects.firstObject];
+ NSExpression *operand = [NSExpression expressionWithMGLJSONObject:argumentObjects.firstObject];
return [NSExpression expressionForFunction:operand selectorName:@"boolValue" arguments:@[]];
- } else if ([op isEqualToString:@"to-number"]) {
- NSExpression *operand = [NSExpression mgl_expressionWithJSONObject:argumentObjects.firstObject];
+ } else if ([op isEqualToString:@"to-number"] || [op isEqualToString:@"number"]) {
+ NSExpression *operand = [NSExpression expressionWithMGLJSONObject:argumentObjects.firstObject];
+ if (argumentObjects.count == 1) {
+ return [NSExpression expressionWithFormat:@"CAST(%@, 'NSNumber')", operand];
+ }
argumentObjects = [argumentObjects subarrayWithRange:NSMakeRange(1, argumentObjects.count - 1)];
NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(argumentObjects);
return [NSExpression expressionForFunction:operand selectorName:@"mgl_numberWithFallbackValues:" arguments:subexpressions];
- } else if ([op isEqualToString:@"to-string"]) {
- NSExpression *operand = [NSExpression mgl_expressionWithJSONObject:argumentObjects.firstObject];
- return [NSExpression expressionForFunction:operand selectorName:@"stringValue" arguments:@[]];
+ } else if ([op isEqualToString:@"to-string"] || [op isEqualToString:@"string"]) {
+ NSExpression *operand = [NSExpression expressionWithMGLJSONObject:argumentObjects.firstObject];
+ return [NSExpression expressionWithFormat:@"CAST(%@, 'NSString')", operand];
} else if ([op isEqualToString:@"get"]) {
if (argumentObjects.count == 2) {
- NSExpression *operand = [NSExpression mgl_expressionWithJSONObject:argumentObjects.lastObject];
+ NSExpression *operand = [NSExpression expressionWithMGLJSONObject:argumentObjects.lastObject];
if ([argumentObjects.firstObject isKindOfClass:[NSString class]]) {
return [NSExpression expressionWithFormat:@"%@.%K", operand, argumentObjects.firstObject];
}
- NSExpression *key = [NSExpression mgl_expressionWithJSONObject:argumentObjects.firstObject];
+ NSExpression *key = [NSExpression expressionWithMGLJSONObject:argumentObjects.firstObject];
return [NSExpression expressionWithFormat:@"%@.%@", operand, key];
}
return [NSExpression expressionForKeyPath:argumentObjects.firstObject];
} else if ([op isEqualToString:@"length"]) {
NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(argumentObjects);
- return [NSExpression expressionForFunction:@"count:" arguments:@[subexpressions.firstObject]];
+ NSString *function = @"count:";
+ if ([subexpressions.firstObject expressionType] == NSConstantValueExpressionType
+ && [[subexpressions.firstObject constantValue] isKindOfClass:[NSString class]]) {
+ function = @"length:";
+ }
+ return [NSExpression expressionForFunction:function arguments:@[subexpressions.firstObject]];
+ } else if ([op isEqualToString:@"rgb"]) {
+ NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(argumentObjects);
+ return [NSExpression mgl_expressionForRGBComponents:subexpressions];
+ } else if ([op isEqualToString:@"rgba"]) {
+ NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(argumentObjects);
+ return [NSExpression mgl_expressionForRGBAComponents:subexpressions];
} else if ([op isEqualToString:@"min"]) {
NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(argumentObjects);
NSExpression *subexpression = [NSExpression expressionForAggregate:subexpressions];
@@ -397,39 +840,47 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
return [NSExpression expressionForConstantValue:@(M_PI)];
} else if ([op isEqualToString:@"concat"]) {
NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(argumentObjects);
- NSExpression *operand = subexpressions.firstObject;
- subexpressions = [subexpressions subarrayWithRange:NSMakeRange(1, subexpressions.count - 1)];
- return [NSExpression expressionForFunction:operand selectorName:@"stringByAppendingString:" arguments:subexpressions];
+ NSExpression *subexpression = [NSExpression expressionForAggregate:subexpressions];
+ return [NSExpression expressionForFunction:@"mgl_join:" arguments:@[subexpression]];
+ } else if ([op isEqualToString:@"at"]) {
+ NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(argumentObjects);
+ NSExpression *index = subexpressions.firstObject;
+ NSExpression *operand = subexpressions[1];
+ return [NSExpression expressionForFunction:@"objectFrom:withIndex:" arguments:@[operand, index]];
+ } else if ([op isEqualToString:@"has"]) {
+ NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(argumentObjects);
+ NSExpression *operand = argumentObjects.count > 1 ? subexpressions[1] : [NSExpression expressionForEvaluatedObject];
+ NSExpression *key = subexpressions.firstObject;
+ return [NSExpression expressionForFunction:@"mgl_does:have:" arguments:@[operand, key]];
} else if ([op isEqualToString:@"interpolate"]) {
NSArray *interpolationOptions = argumentObjects.firstObject;
NSString *curveType = interpolationOptions.firstObject;
- NSExpression *curveTypeExpression = [NSExpression mgl_expressionWithJSONObject:curveType];
+ NSExpression *curveTypeExpression = [NSExpression expressionWithMGLJSONObject:curveType];
id curveParameters;
if ([curveType isEqual:@"exponential"]) {
curveParameters = interpolationOptions[1];
} else if ([curveType isEqualToString:@"cubic-bezier"]) {
curveParameters = @[@"literal", [interpolationOptions subarrayWithRange:NSMakeRange(1, 4)]];
}
- NSExpression *curveParameterExpression = [NSExpression mgl_expressionWithJSONObject:curveParameters];
+ NSExpression *curveParameterExpression = [NSExpression expressionWithMGLJSONObject:curveParameters];
argumentObjects = [argumentObjects subarrayWithRange:NSMakeRange(1, argumentObjects.count - 1)];
- NSExpression *operand = [NSExpression mgl_expressionWithJSONObject:argumentObjects.firstObject];
+ NSExpression *inputExpression = [NSExpression expressionWithMGLJSONObject:argumentObjects.firstObject];
NSArray *stopExpressions = [argumentObjects subarrayWithRange:NSMakeRange(1, argumentObjects.count - 1)];
NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:stopExpressions.count / 2];
NSEnumerator *stopEnumerator = stopExpressions.objectEnumerator;
while (NSNumber *key = stopEnumerator.nextObject) {
NSExpression *valueExpression = stopEnumerator.nextObject;
- stops[key] = [NSExpression mgl_expressionWithJSONObject:valueExpression];
+ stops[key] = [NSExpression expressionWithMGLJSONObject:valueExpression];
}
NSExpression *stopExpression = [NSExpression expressionForConstantValue:stops];
- return [NSExpression expressionForFunction:operand
- selectorName:@"mgl_interpolateWithCurveType:parameters:stops:"
- arguments:@[curveTypeExpression, curveParameterExpression, stopExpression]];
+ return [NSExpression expressionForFunction:@"mgl_interpolate:withCurveType:parameters:stops:"
+ arguments:@[inputExpression, curveTypeExpression, curveParameterExpression, stopExpression]];
} else if ([op isEqualToString:@"step"]) {
- NSExpression *operand = [NSExpression mgl_expressionWithJSONObject:argumentObjects[0]];
+ NSExpression *inputExpression = [NSExpression expressionWithMGLJSONObject:argumentObjects[0]];
NSArray *stopExpressions = [argumentObjects subarrayWithRange:NSMakeRange(1, argumentObjects.count - 1)];
NSExpression *minimum;
if (stopExpressions.count % 2) {
- minimum = [NSExpression mgl_expressionWithJSONObject:stopExpressions.firstObject];
+ minimum = [NSExpression expressionWithMGLJSONObject:stopExpressions.firstObject];
stopExpressions = [stopExpressions subarrayWithRange:NSMakeRange(1, stopExpressions.count - 1)];
}
NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:stopExpressions.count / 2];
@@ -437,47 +888,66 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
while (NSNumber *key = stopEnumerator.nextObject) {
NSExpression *valueExpression = stopEnumerator.nextObject;
if (minimum) {
- stops[key] = [NSExpression mgl_expressionWithJSONObject:valueExpression];
+ stops[key] = [NSExpression expressionWithMGLJSONObject:valueExpression];
} else {
- minimum = [NSExpression mgl_expressionWithJSONObject:valueExpression];
+ minimum = [NSExpression expressionWithMGLJSONObject:valueExpression];
}
}
NSExpression *stopExpression = [NSExpression expressionForConstantValue:stops];
- return [NSExpression expressionForFunction:operand
- selectorName:@"mgl_stepWithMinimum:stops:"
- arguments:@[minimum, stopExpression]];
+ return [NSExpression expressionForFunction:@"mgl_step:from:stops:"
+ arguments:@[inputExpression, minimum, stopExpression]];
} else if ([op isEqualToString:@"zoom"]) {
- return [NSExpression expressionForVariable:@"zoomLevel"];
+ return NSExpression.zoomLevelVariableExpression;
} else if ([op isEqualToString:@"heatmap-density"]) {
- return [NSExpression expressionForVariable:@"heatmapDensity"];
- } else if ([op isEqualToString:@"let"]) {
- NSExpression *operand = [NSExpression mgl_expressionWithJSONObject:argumentObjects.lastObject];
- NSArray *bindingObjects = [argumentObjects subarrayWithRange:NSMakeRange(0, argumentObjects.count - 1)];
- NSMutableDictionary *context = [NSMutableDictionary dictionaryWithCapacity:bindingObjects.count / 2];
- NSEnumerator *bindingEnumerator = bindingObjects.objectEnumerator;
- while (NSString *key = bindingEnumerator.nextObject) {
- context[key] = [NSExpression mgl_expressionWithJSONObject:bindingEnumerator.nextObject];
- }
- return [NSExpression expressionForFunction:operand
- selectorName:@"mgl_expressionWithContext:"
- arguments:@[[NSExpression expressionForConstantValue:context]]];
+ return NSExpression.heatmapDensityVariableExpression;
+ } else if ([op isEqualToString:@"geometry-type"]) {
+ return NSExpression.geometryTypeVariableExpression;
+ } else if ([op isEqualToString:@"id"]) {
+ return NSExpression.featureIdentifierVariableExpression;
+ } else if ([op isEqualToString:@"properties"]) {
+ return NSExpression.featureAttributesVariableExpression;
} else if ([op isEqualToString:@"var"]) {
return [NSExpression expressionForVariable:argumentObjects.firstObject];
} else if ([op isEqualToString:@"case"]) {
- NSPredicate *conditional = [NSPredicate mgl_predicateWithJSONObject:argumentObjects.firstObject];
- NSExpression *trueExpression = [NSExpression mgl_expressionWithJSONObject:argumentObjects[1]];
- NSExpression *falseExpression;
- if (argumentObjects.count > 3) {
- NSArray *falseObjects = [@[@"case"] arrayByAddingObjectsFromArray:
- [argumentObjects subarrayWithRange:NSMakeRange(2, argumentObjects.count - 2)]];
- falseExpression = [NSExpression mgl_expressionWithJSONObject:falseObjects];
- } else {
- falseExpression = [NSExpression mgl_expressionWithJSONObject:argumentObjects[2]];
+ NSMutableArray *arguments = [NSMutableArray array];
+
+ for (NSUInteger index = 0; index < argumentObjects.count; index++) {
+ if (index % 2 == 0 && index != argumentObjects.count - 1) {
+ NSPredicate *predicate = [NSPredicate mgl_predicateWithJSONObject:argumentObjects[index]];
+ NSExpression *argument = [NSExpression expressionForConstantValue:predicate];
+ [arguments addObject:argument];
+ } else {
+ [arguments addObject:[NSExpression expressionWithMGLJSONObject:argumentObjects[index]]];
+ }
}
- return [NSExpression expressionForConditional:conditional trueExpression:trueExpression falseExpression:falseExpression];
+
+ if (@available(iOS 9.0, *)) {
+ if (arguments.count == 3) {
+ NSPredicate *conditional = [arguments.firstObject constantValue];
+ return [NSExpression expressionForConditional:conditional trueExpression:arguments[1] falseExpression:arguments[2]];
+ }
+ }
+ return [NSExpression expressionForFunction:@"MGL_IF" arguments:arguments];
+ } else if ([op isEqualToString:@"match"]) {
+ NSMutableArray *optionsArray = [NSMutableArray array];
+ NSEnumerator *optionsEnumerator = argumentObjects.objectEnumerator;
+ while (id object = optionsEnumerator.nextObject) {
+ NSExpression *option = [NSExpression expressionWithMGLJSONObject:object];
+ [optionsArray addObject:option];
+ }
+
+ return [NSExpression expressionForFunction:@"MGL_MATCH"
+ arguments:optionsArray];
+ } else if ([op isEqualToString:@"coalesce"]) {
+ NSMutableArray *expressions = [NSMutableArray array];
+ for (id operand in argumentObjects) {
+ [expressions addObject:[NSExpression expressionWithMGLJSONObject:operand]];
+ }
+
+ return [NSExpression expressionWithFormat:@"mgl_coalesce(%@)", expressions];
} else {
- [NSException raise:NSInvalidArgumentException
- format:@"Expression operator %@ not yet implemented.", op];
+ NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(array);
+ return [NSExpression expressionForFunction:@"MGL_FUNCTION" arguments:subexpressions];
}
}
@@ -500,8 +970,23 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
@"log:": @"log10",
@"ln:": @"ln",
@"raise:toPower:": @"^",
+ @"ceiling:": @"ceil",
+ @"abs:": @"abs",
+ @"floor:": @"floor",
@"uppercase:": @"upcase",
@"lowercase:": @"downcase",
+ @"length:": @"length",
+ @"mgl_round:": @"round",
+ @"mgl_acos:" : @"acos",
+ @"mgl_cos:" : @"cos",
+ @"mgl_asin:" : @"asin",
+ @"mgl_sin:" : @"sin",
+ @"mgl_atan:" : @"atan",
+ @"mgl_tan:" : @"tan",
+ @"mgl_log2:" : @"log2",
+ // Vararg aftermarket expressions need to be declared with an explicit and implicit first argument.
+ @"MGL_LET": @"let",
+ @"MGL_LET:": @"let",
};
});
@@ -513,6 +998,15 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
if ([self.variable isEqualToString:@"zoomLevel"]) {
return @[@"zoom"];
}
+ if ([self.variable isEqualToString:@"geometryType"]) {
+ return @[@"geometry-type"];
+ }
+ if ([self.variable isEqualToString:@"featureIdentifier"]) {
+ return @[@"id"];
+ }
+ if ([self.variable isEqualToString:@"featureAttributes"]) {
+ return @[@"properties"];
+ }
return @[@"var", self.variable];
}
@@ -573,7 +1067,7 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
if (op) {
NSArray *arguments = self.arguments.mgl_jsonExpressionObject;
return [@[op] arrayByAddingObjectsFromArray:arguments];
- } else if ([function isEqualToString:@"valueForKeyPath:"]) {
+ } else if ([function isEqualToString:@"valueForKey:"] || [function isEqualToString:@"valueForKeyPath:"]) {
return @[@"get", self.arguments.firstObject.mgl_jsonExpressionObject, self.operand.mgl_jsonExpressionObject];
} else if ([function isEqualToString:@"average:"]) {
NSExpression *sum = [NSExpression expressionForFunction:@"sum:" arguments:self.arguments];
@@ -593,24 +1087,21 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
return [@[@"max"] arrayByAddingObjectsFromArray:arguments];
} else if ([function isEqualToString:@"exp:"]) {
return [NSExpression expressionForFunction:@"raise:toPower:" arguments:@[@(M_E), self.arguments.firstObject]].mgl_jsonExpressionObject;
- } else if ([function isEqualToString:@"ceiling:"]) {
- return [NSExpression expressionWithFormat:@"trunc:(%@) + TERNARY(modulus:by:(%@, 1) > 0, 1, 0)",
- self.arguments.firstObject, self.arguments.firstObject].mgl_jsonExpressionObject;
} else if ([function isEqualToString:@"trunc:"]) {
return [NSExpression expressionWithFormat:@"%@ - modulus:by:(%@, 1)",
self.arguments.firstObject, self.arguments.firstObject].mgl_jsonExpressionObject;
- } else if ([function isEqualToString:@"abs:"]) {
- return [NSExpression expressionWithFormat:@"%@ * TERNARY(%@ > 0, 1, -1)",
- self.arguments.firstObject, self.arguments.firstObject].mgl_jsonExpressionObject;
- } else if ([function isEqualToString:@"floor:"]) {
- return [NSExpression expressionWithFormat:@"trunc:(%@) - TERNARY(modulus:by:(%@, 1) < 0, 1, 0)",
- self.arguments.firstObject, self.arguments.firstObject].mgl_jsonExpressionObject;
+ } else if ([function isEqualToString:@"mgl_join:"]) {
+ NSArray *arguments = [self.arguments.firstObject.collection valueForKeyPath:@"mgl_jsonExpressionObject"];
+ return [@[@"concat"] arrayByAddingObjectsFromArray:arguments];
} else if ([function isEqualToString:@"stringByAppendingString:"]) {
NSArray *arguments = self.arguments.mgl_jsonExpressionObject;
return [@[@"concat", self.operand.mgl_jsonExpressionObject] arrayByAddingObjectsFromArray:arguments];
+ } else if ([function isEqualToString:@"objectFrom:withIndex:"]) {
+ return @[@"at", self.arguments[1].mgl_jsonExpressionObject, self.arguments[0].mgl_jsonExpressionObject];
} else if ([function isEqualToString:@"boolValue"]) {
return @[@"to-boolean", self.operand.mgl_jsonExpressionObject];
- } else if ([function isEqualToString:@"mgl_numberWithFallbackValues:"] ||
+ } else if ([function isEqualToString:@"mgl_number"] ||
+ [function isEqualToString:@"mgl_numberWithFallbackValues:"] ||
[function isEqualToString:@"decimalValue"] ||
[function isEqualToString:@"floatValue"] ||
[function isEqualToString:@"doubleValue"]) {
@@ -620,40 +1111,15 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
return @[@"to-string", self.operand.mgl_jsonExpressionObject];
} else if ([function isEqualToString:@"noindex:"]) {
return self.arguments.firstObject.mgl_jsonExpressionObject;
- } else if ([function isEqualToString:@"mgl_interpolateWithCurveType:parameters:stops:"]) {
- if (self.arguments.count < 3) {
- [NSException raise:NSInvalidArgumentException format:
- @"Too few arguments to ‘mgl_interpolateWithCurveType:parameters:stops:’ function; expected 3 arguments."];
- } else if (self.arguments.count > 3) {
- [NSException raise:NSInvalidArgumentException format:
- @"%lu unexpected arguments to ‘mgl_interpolateWithCurveType:parameters:stops:’ function; expected 3 arguments.",
- self.arguments.count - 3];
- }
- NSString *curveType = self.arguments.firstObject.constantValue;
- NSMutableArray *interpolationArray = [NSMutableArray arrayWithObject:curveType];
- if ([curveType isEqualToString:@"exponential"]) {
- id base = [self.arguments[1] mgl_jsonExpressionObject];
- [interpolationArray addObject:base];
- } else if ([curveType isEqualToString:@"cubic-bezier"]) {
- NSArray *controlPoints = [self.arguments[1].collection mgl_jsonExpressionObject];
- [interpolationArray addObjectsFromArray:controlPoints];
- }
- NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"interpolate", interpolationArray, self.operand.mgl_jsonExpressionObject, nil];
- NSDictionary<NSNumber *, NSExpression *> *stops = self.arguments[2].constantValue;
- for (NSNumber *key in [stops.allKeys sortedArrayUsingSelector:@selector(compare:)]) {
- [expressionObject addObject:key];
- [expressionObject addObject:[stops[key] mgl_jsonExpressionObject]];
- }
- return expressionObject;
- } else if ([function isEqualToString:@"mgl_stepWithMinimum:stops:"]) {
- id minimum = self.arguments.firstObject.mgl_jsonExpressionObject;
- NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"step", self.operand.mgl_jsonExpressionObject, minimum, nil];
- NSDictionary<NSNumber *, NSExpression *> *stops = self.arguments[1].constantValue;
- for (NSNumber *key in [stops.allKeys sortedArrayUsingSelector:@selector(compare:)]) {
- [expressionObject addObject:key];
- [expressionObject addObject:[stops[key] mgl_jsonExpressionObject]];
- }
- return expressionObject;
+ } else if ([function isEqualToString:@"mgl_does:have:"] ||
+ [function isEqualToString:@"mgl_has:"]) {
+ return self.mgl_jsonHasExpressionObject;
+ } else if ([function isEqualToString:@"mgl_interpolate:withCurveType:parameters:stops:"]
+ || [function isEqualToString:@"mgl_interpolateWithCurveType:parameters:stops:"]) {
+ return self.mgl_jsonInterpolationExpressionObject;
+ } else if ([function isEqualToString:@"mgl_step:from:stops:"]
+ || [function isEqualToString:@"mgl_stepWithMinimum:stops:"]) {
+ return self.mgl_jsonStepExpressionObject;
} else if ([function isEqualToString:@"mgl_expressionWithContext:"]) {
id context = self.arguments.firstObject;
if ([context isKindOfClass:[NSExpression class]]) {
@@ -666,6 +1132,31 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
}];
[expressionObject addObject:self.operand.mgl_jsonExpressionObject];
return expressionObject;
+ } else if ([function isEqualToString:@"MGL_IF"] ||
+ [function isEqualToString:@"mgl_if:"]) {
+ return self.mgl_jsonIfExpressionObject;
+ } else if ([function isEqualToString:@"MGL_MATCH"] ||
+ [function isEqualToString:@"mgl_match:"]) {
+ return self.mgl_jsonMatchExpressionObject;
+ } else if ([function isEqualToString:@"mgl_coalesce:"] ||
+ [function isEqualToString:@"mgl_coalesce"]) {
+
+ return self.mgl_jsonCoalesceExpressionObject;
+ } else if ([function isEqualToString:@"castObject:toType:"]) {
+ id object = self.arguments.firstObject.mgl_jsonExpressionObject;
+ NSString *type = self.arguments[1].mgl_jsonExpressionObject;
+ if ([type isEqualToString:@"NSString"]) {
+ return @[@"to-string", object];
+ } else if ([type isEqualToString:@"NSNumber"]) {
+ return @[@"to-number", object];
+ }
+ [NSException raise:NSInvalidArgumentException
+ format:@"Casting expression to %@ not yet implemented.", type];
+ } else if ([function isEqualToString:@"MGL_FUNCTION"]) {
+ return self.arguments.mgl_jsonExpressionObject;
+ } else if (op == [MGLColor class] && [function isEqualToString:@"colorWithRed:green:blue:alpha:"]) {
+ NSArray *arguments = self.arguments.mgl_jsonExpressionObject;
+ return [@[@"rgba"] arrayByAddingObjectsFromArray:arguments];
} else if ([function isEqualToString:@"median:"] ||
[function isEqualToString:@"mode:"] ||
[function isEqualToString:@"stddev:"] ||
@@ -690,7 +1181,17 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
}
case NSConditionalExpressionType: {
- NSMutableArray *arguments = [NSMutableArray arrayWithObjects:self.predicate.mgl_jsonExpressionObject, self.trueExpression.mgl_jsonExpressionObject, nil];
+ NSMutableArray *arguments = [NSMutableArray arrayWithObjects:self.predicate.mgl_jsonExpressionObject, nil];
+
+ if (self.trueExpression.expressionType == NSConditionalExpressionType) {
+ // Fold nested conditionals into a single case expression.
+ NSArray *trueArguments = self.trueExpression.mgl_jsonExpressionObject;
+ trueArguments = [trueArguments subarrayWithRange:NSMakeRange(1, trueArguments.count - 1)];
+ [arguments addObjectsFromArray:trueArguments];
+ } else {
+ [arguments addObject:self.trueExpression.mgl_jsonExpressionObject];
+ }
+
if (self.falseExpression.expressionType == NSConditionalExpressionType) {
// Fold nested conditionals into a single case expression.
NSArray *falseArguments = self.falseExpression.mgl_jsonExpressionObject;
@@ -734,4 +1235,243 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
return nil;
}
+- (id)mgl_jsonInterpolationExpressionObject {
+ NSUInteger expectedArgumentCount = [self.function componentsSeparatedByString:@":"].count - 1;
+ if (self.arguments.count < expectedArgumentCount) {
+ [NSException raise:NSInvalidArgumentException format:
+ @"Too few arguments to ‘%@’ function; expected %lu arguments.",
+ self.function, expectedArgumentCount];
+ } else if (self.arguments.count > expectedArgumentCount) {
+ [NSException raise:NSInvalidArgumentException format:
+ @"%lu unexpected arguments to ‘%@’ function; expected %lu arguments.",
+ self.arguments.count - expectedArgumentCount, self.function, expectedArgumentCount];
+ }
+
+ BOOL isAftermarketFunction = [self.function isEqualToString:@"mgl_interpolate:withCurveType:parameters:stops:"];
+ NSUInteger curveTypeIndex = isAftermarketFunction ? 1 : 0;
+ NSString *curveType = self.arguments[curveTypeIndex].constantValue;
+ NSMutableArray *interpolationArray = [NSMutableArray arrayWithObject:curveType];
+ if ([curveType isEqualToString:@"exponential"]) {
+ id base = [self.arguments[curveTypeIndex + 1] mgl_jsonExpressionObject];
+ [interpolationArray addObject:base];
+ } else if ([curveType isEqualToString:@"cubic-bezier"]) {
+ NSArray *controlPoints = [self.arguments[curveTypeIndex + 1].collection mgl_jsonExpressionObject];
+ [interpolationArray addObjectsFromArray:controlPoints];
+ }
+ NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"interpolate", interpolationArray, nil];
+ [expressionObject addObject:(isAftermarketFunction ? self.arguments.firstObject : self.operand).mgl_jsonExpressionObject];
+ NSDictionary<NSNumber *, NSExpression *> *stops = self.arguments[curveTypeIndex + 2].constantValue;
+ for (NSNumber *key in [stops.allKeys sortedArrayUsingSelector:@selector(compare:)]) {
+ [expressionObject addObject:key];
+ [expressionObject addObject:[stops[key] mgl_jsonExpressionObject]];
+ }
+ return expressionObject;
+}
+
+- (id)mgl_jsonStepExpressionObject {
+ BOOL isAftermarketFunction = [self.function isEqualToString:@"mgl_step:from:stops:"];
+ NSUInteger minimumIndex = isAftermarketFunction ? 1 : 0;
+ id minimum = self.arguments[minimumIndex].mgl_jsonExpressionObject;
+ NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"step", (isAftermarketFunction ? self.arguments.firstObject : self.operand).mgl_jsonExpressionObject, minimum, nil];
+ NSDictionary<NSNumber *, NSExpression *> *stops = self.arguments[minimumIndex + 1].constantValue;
+ for (NSNumber *key in [stops.allKeys sortedArrayUsingSelector:@selector(compare:)]) {
+ [expressionObject addObject:key];
+ [expressionObject addObject:[stops[key] mgl_jsonExpressionObject]];
+ }
+ return expressionObject;
+}
+
+- (id)mgl_jsonMatchExpressionObject {
+ BOOL isAftermarketFunction = [self.function isEqualToString:@"MGL_MATCH"];
+ NSUInteger minimumIndex = isAftermarketFunction ? 1 : 0;
+
+ NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"match", (isAftermarketFunction ? self.arguments.firstObject : self.operand).mgl_jsonExpressionObject, nil];
+ NSArray<NSExpression *> *arguments = isAftermarketFunction ? self.arguments : self.arguments[minimumIndex].constantValue;
+
+ for (NSUInteger index = minimumIndex; index < arguments.count; index++) {
+ [expressionObject addObject:arguments[index].mgl_jsonExpressionObject];
+ }
+
+ return expressionObject;
+}
+
+- (id)mgl_jsonIfExpressionObject {
+ BOOL isAftermarketFunction = [self.function isEqualToString:@"MGL_IF"];
+ NSUInteger minimumIndex = isAftermarketFunction ? 1 : 0;
+ NSExpression *firstCondition;
+ id condition;
+
+ if (isAftermarketFunction) {
+ firstCondition = self.arguments.firstObject;
+ } else {
+ firstCondition = self.operand;
+ }
+
+ if ([firstCondition respondsToSelector:@selector(constantValue)] && [firstCondition.constantValue isKindOfClass:[NSComparisonPredicate class]]) {
+ NSPredicate *predicate = (NSPredicate *)firstCondition.constantValue;
+ condition = predicate.mgl_jsonExpressionObject;
+ } else {
+ condition = firstCondition.mgl_jsonExpressionObject;
+ }
+
+ NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"case", condition, nil];
+ NSArray<NSExpression *> *arguments = isAftermarketFunction ? self.arguments : self.arguments[minimumIndex].constantValue;
+
+ for (NSUInteger index = minimumIndex; index < arguments.count; index++) {
+ if ([arguments[index] respondsToSelector:@selector(constantValue)] && [arguments[index].constantValue isKindOfClass:[NSComparisonPredicate class]]) {
+ NSPredicate *predicate = (NSPredicate *)arguments[index].constantValue;
+ [expressionObject addObject:predicate.mgl_jsonExpressionObject];
+ } else {
+ [expressionObject addObject:arguments[index].mgl_jsonExpressionObject];
+ }
+ }
+
+ return expressionObject;
+}
+
+- (id)mgl_jsonCoalesceExpressionObject {
+ BOOL isAftermarketFunction = [self.function isEqualToString:@"mgl_coalesce:"];
+ NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"coalesce", nil];
+
+ for (NSExpression *expression in (isAftermarketFunction ? self.arguments.firstObject : self.operand).constantValue) {
+ [expressionObject addObject:[expression mgl_jsonExpressionObject]];
+ }
+
+ return expressionObject;
+}
+
+- (id)mgl_jsonHasExpressionObject {
+ BOOL isAftermarketFunction = [self.function isEqualToString:@"mgl_does:have:"];
+ NSExpression *operand = isAftermarketFunction ? self.arguments[0] : self.operand;
+ NSExpression *key = self.arguments[isAftermarketFunction ? 1 : 0];
+
+ NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"has", key.mgl_jsonExpressionObject, nil];
+ if (operand.expressionType != NSEvaluatedObjectExpressionType) {
+ [expressionObject addObject:operand.mgl_jsonExpressionObject];
+ }
+ return expressionObject;
+}
+
+#pragma mark Localization
+
+/**
+ Returns a localized copy of the given collection.
+
+ If no localization takes place, this method returns the original collection.
+ */
+NS_ARRAY_OF(NSExpression *) *MGLLocalizedCollection(NS_ARRAY_OF(NSExpression *) *collection, NSLocale * _Nullable locale) {
+ __block NSMutableArray *localizedCollection;
+ [collection enumerateObjectsUsingBlock:^(NSExpression * _Nonnull item, NSUInteger idx, BOOL * _Nonnull stop) {
+ NSExpression *localizedItem = [item mgl_expressionLocalizedIntoLocale:locale];
+ if (localizedItem != item) {
+ if (!localizedCollection) {
+ localizedCollection = [collection mutableCopy];
+ }
+ localizedCollection[idx] = localizedItem;
+ }
+ }];
+ return localizedCollection ?: collection;
+};
+
+/**
+ Returns a localized copy of the given stop dictionary.
+
+ If no localization takes place, this method returns the original stop
+ dictionary.
+ */
+NS_DICTIONARY_OF(NSNumber *, NSExpression *) *MGLLocalizedStopDictionary(NS_DICTIONARY_OF(NSNumber *, NSExpression *) *stops, NSLocale * _Nullable locale) {
+ __block NSMutableDictionary *localizedStops;
+ [stops enumerateKeysAndObjectsUsingBlock:^(id _Nonnull zoomLevel, NSExpression * _Nonnull value, BOOL * _Nonnull stop) {
+ if (![value isKindOfClass:[NSExpression class]]) {
+ value = [NSExpression expressionForConstantValue:value];
+ }
+ NSExpression *localizedValue = [value mgl_expressionLocalizedIntoLocale:locale];
+ if (localizedValue != value) {
+ if (!localizedStops) {
+ localizedStops = [stops mutableCopy];
+ }
+ localizedStops[zoomLevel] = localizedValue;
+ }
+ }];
+ return localizedStops ?: stops;
+};
+
+- (NSExpression *)mgl_expressionLocalizedIntoLocale:(nullable NSLocale *)locale {
+ switch (self.expressionType) {
+ case NSConstantValueExpressionType: {
+ NSDictionary *stops = self.constantValue;
+ if ([stops isKindOfClass:[NSDictionary class]]) {
+ NSDictionary *localizedStops = MGLLocalizedStopDictionary(stops, locale);
+ if (localizedStops != stops) {
+ return [NSExpression expressionForConstantValue:localizedStops];
+ }
+ }
+ return self;
+ }
+
+ case NSKeyPathExpressionType: {
+ if ([self.keyPath isEqualToString:@"name"] || [self.keyPath hasPrefix:@"name_"]) {
+ NSString *localizedKeyPath = @"name";
+ if (![locale.localeIdentifier isEqualToString:@"mul"]) {
+ NSArray *preferences = locale ? @[locale.localeIdentifier] : [NSLocale preferredLanguages];
+ NSString *preferredLanguage = [MGLVectorTileSource preferredMapboxStreetsLanguageForPreferences:preferences];
+ if (preferredLanguage) {
+ localizedKeyPath = [NSString stringWithFormat:@"name_%@", preferredLanguage];
+ }
+ }
+ return [NSExpression expressionForKeyPath:localizedKeyPath];
+ }
+ return self;
+ }
+
+ case NSFunctionExpressionType: {
+ NSExpression *operand = self.operand;
+ NSExpression *localizedOperand = [operand mgl_expressionLocalizedIntoLocale:locale];
+
+ NSArray *arguments = self.arguments;
+ NSArray *localizedArguments = MGLLocalizedCollection(arguments, locale);
+ if (localizedArguments != arguments) {
+ return [NSExpression expressionForFunction:localizedOperand
+ selectorName:self.function
+ arguments:localizedArguments];
+ }
+ if (localizedOperand != operand) {
+ return [NSExpression expressionForFunction:localizedOperand
+ selectorName:self.function
+ arguments:self.arguments];
+ }
+ return self;
+ }
+
+ case NSConditionalExpressionType: {
+ if (@available(iOS 9.0, *)) {
+ NSExpression *trueExpression = self.trueExpression;
+ NSExpression *localizedTrueExpression = [trueExpression mgl_expressionLocalizedIntoLocale:locale];
+ NSExpression *falseExpression = self.falseExpression;
+ NSExpression *localizedFalseExpression = [falseExpression mgl_expressionLocalizedIntoLocale:locale];
+ if (localizedTrueExpression != trueExpression || localizedFalseExpression != falseExpression) {
+ return [NSExpression expressionForConditional:self.predicate
+ trueExpression:localizedTrueExpression
+ falseExpression:localizedFalseExpression];
+ }
+ }
+ return self;
+ }
+
+ case NSAggregateExpressionType: {
+ NSArray *collection = self.collection;
+ if ([collection isKindOfClass:[NSArray class]]) {
+ NSArray *localizedCollection = MGLLocalizedCollection(collection, locale);
+ if (localizedCollection != collection) {
+ return [NSExpression expressionForAggregate:localizedCollection];
+ }
+ }
+ return self;
+ }
+
+ default:
+ return self;
+ }
+}
+
@end
diff --git a/platform/darwin/src/NSExpression+MGLPrivateAdditions.h b/platform/darwin/src/NSExpression+MGLPrivateAdditions.h
index 8d1b4d6af5..a1948f9e45 100644
--- a/platform/darwin/src/NSExpression+MGLPrivateAdditions.h
+++ b/platform/darwin/src/NSExpression+MGLPrivateAdditions.h
@@ -27,6 +27,11 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) mbgl::FeatureIdentifier mgl_featureIdentifier;
@property (nonatomic, readonly) std::vector<mbgl::FeatureIdentifier> mgl_aggregateFeatureIdentifier;
+/**
+ Returns a copy of the receiver with tokens replaced by key path expressions.
+ */
+- (NSExpression *)mgl_expressionByReplacingTokensWithKeyPaths;
+
@end
@interface NSNull (MGLExpressionAdditions)
@@ -60,6 +65,8 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) id mgl_jsonExpressionObject;
+- (id)mgl_has:(id)element;
+
@end
@interface MGLColor (MGLExpressionAdditions)
@@ -72,6 +79,9 @@ NS_ASSUME_NONNULL_BEGIN
- (NSExpression *)mgl_expressionWithContext:(NSDictionary<NSString *, NSExpression *> *)context;
+
+- (id)mgl_has:(id)element;
+
@end
extern NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects);
diff --git a/platform/darwin/src/NSPredicate+MGLAdditions.h b/platform/darwin/src/NSPredicate+MGLAdditions.h
index 89e9e65c64..a73b1a61ba 100644
--- a/platform/darwin/src/NSPredicate+MGLAdditions.h
+++ b/platform/darwin/src/NSPredicate+MGLAdditions.h
@@ -16,4 +16,8 @@
@property (nonatomic, readonly) id mgl_jsonExpressionObject;
+- (id)mgl_if:(id)firstValue, ...;
+
+- (id)mgl_match:(NSExpression *)firstCase, ...;
+
@end
diff --git a/platform/darwin/src/NSPredicate+MGLAdditions.mm b/platform/darwin/src/NSPredicate+MGLAdditions.mm
index 63c8307803..bbd324bb63 100644
--- a/platform/darwin/src/NSPredicate+MGLAdditions.mm
+++ b/platform/darwin/src/NSPredicate+MGLAdditions.mm
@@ -3,6 +3,8 @@
#import "MGLValueEvaluator.h"
#import "MGLStyleValue_Private.h"
+#include <mbgl/style/conversion/filter.hpp>
+
class FilterEvaluator {
public:
@@ -206,25 +208,18 @@ public:
- (mbgl::style::Filter)mgl_filter
{
- if ([self isEqual:[NSPredicate predicateWithValue:YES]])
- {
- return mbgl::style::AllFilter();
- }
-
- if ([self isEqual:[NSPredicate predicateWithValue:NO]])
- {
- return mbgl::style::AnyFilter();
- }
-
- if ([self.predicateFormat hasPrefix:@"BLOCKPREDICATE("])
- {
+ mbgl::style::conversion::Error valueError;
+ NSArray *jsonObject = self.mgl_jsonExpressionObject;
+ auto value = mbgl::style::conversion::convert<mbgl::style::Filter>(mbgl::style::conversion::makeConvertible(jsonObject), valueError);
+
+ if (!value) {
[NSException raise:NSInvalidArgumentException
- format:@"Block-based predicates are not supported."];
+ format:@"Invalid filter value: %@", @(valueError.message.c_str())];
+ return {};
}
-
- [NSException raise:NSInvalidArgumentException
- format:@"Unrecognized predicate type."];
- return {};
+ mbgl::style::Filter filter = std::move(*value);
+
+ return filter;
}
+ (instancetype)mgl_predicateWithFilter:(mbgl::style::Filter)filter
@@ -280,7 +275,7 @@ NSArray *MGLSubpredicatesWithJSONObjects(NSArray *objects) {
}
if ([op isEqualToString:@">="]) {
NSArray *subexpressions = MGLSubexpressionsWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
- return [NSPredicate predicateWithFormat:@"%K >= %@" argumentArray:subexpressions];
+ return [NSPredicate predicateWithFormat:@"%@ >= %@" argumentArray:subexpressions];
}
if ([op isEqualToString:@"!"]) {
NSArray *subpredicates = MGLSubpredicatesWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
@@ -294,7 +289,43 @@ NSArray *MGLSubpredicatesWithJSONObjects(NSArray *objects) {
return [NSPredicate predicateWithValue:YES];
}
if ([op isEqualToString:@"all"]) {
- NSArray *subpredicates = MGLSubpredicatesWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
+ NSArray<NSPredicate *> *subpredicates = MGLSubpredicatesWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
+ if (subpredicates.count == 2) {
+ // Determine if the expression is of BETWEEN type
+ if ([subpredicates[0] isKindOfClass:[NSComparisonPredicate class]] &&
+ [subpredicates[1] isKindOfClass:[NSComparisonPredicate class]]) {
+ NSComparisonPredicate *leftCondition = (NSComparisonPredicate *)subpredicates[0];
+ NSComparisonPredicate *rightCondition = (NSComparisonPredicate *)subpredicates[1];
+
+ NSArray *limits;
+ NSExpression *leftConditionExpression;
+
+ if(leftCondition.predicateOperatorType == NSGreaterThanOrEqualToPredicateOperatorType &&
+ rightCondition.predicateOperatorType == NSLessThanOrEqualToPredicateOperatorType) {
+ limits = @[leftCondition.rightExpression, rightCondition.rightExpression];
+ leftConditionExpression = leftCondition.leftExpression;
+
+ } else if (leftCondition.predicateOperatorType == NSLessThanOrEqualToPredicateOperatorType &&
+ rightCondition.predicateOperatorType == NSLessThanOrEqualToPredicateOperatorType) {
+ limits = @[leftCondition.leftExpression, rightCondition.rightExpression];
+ leftConditionExpression = leftCondition.rightExpression;
+
+ } else if(leftCondition.predicateOperatorType == NSLessThanOrEqualToPredicateOperatorType &&
+ rightCondition.predicateOperatorType == NSGreaterThanOrEqualToPredicateOperatorType) {
+ limits = @[leftCondition.leftExpression, rightCondition.leftExpression];
+ leftConditionExpression = leftCondition.rightExpression;
+
+ } else if(leftCondition.predicateOperatorType == NSGreaterThanOrEqualToPredicateOperatorType &&
+ rightCondition.predicateOperatorType == NSGreaterThanOrEqualToPredicateOperatorType) {
+ limits = @[leftCondition.rightExpression, rightCondition.leftExpression];
+ leftConditionExpression = leftCondition.leftExpression;
+ }
+
+ if (limits && leftConditionExpression) {
+ return [NSPredicate predicateWithFormat:@"%@ BETWEEN %@", leftConditionExpression, [NSExpression expressionForAggregate:limits]];
+ }
+ }
+ }
return [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
}
if ([op isEqualToString:@"any"]) {
@@ -302,8 +333,13 @@ NSArray *MGLSubpredicatesWithJSONObjects(NSArray *objects) {
return [NSCompoundPredicate orPredicateWithSubpredicates:subpredicates];
}
- NSAssert(NO, @"Unrecognized expression conditional operator %@.", op);
- return nil;
+ NSExpression *expression = [NSExpression expressionWithMGLJSONObject:object];
+ return [NSComparisonPredicate predicateWithLeftExpression:expression
+ rightExpression:[NSExpression expressionForConstantValue:@YES]
+ modifier:NSDirectPredicateModifier
+ type:NSEqualToPredicateOperatorType
+ options:0];
+
}
- (id)mgl_jsonExpressionObject {
@@ -324,4 +360,35 @@ NSArray *MGLSubpredicatesWithJSONObjects(NSArray *objects) {
return nil;
}
+- (id)mgl_if:(id)firstValue, ... {
+
+ if ([self evaluateWithObject:nil]) {
+ return firstValue;
+ }
+
+ id eachExpression;
+ va_list argumentList;
+ va_start(argumentList, firstValue);
+
+ while ((eachExpression = va_arg(argumentList, id))) {
+ if ([eachExpression isKindOfClass:[NSComparisonPredicate class]]) {
+ id valueExpression = va_arg(argumentList, id);
+ if ([eachExpression evaluateWithObject:nil]) {
+ return valueExpression;
+ }
+ } else {
+ return eachExpression;
+ }
+ }
+ va_end(argumentList);
+
+ return nil;
+}
+
+- (id)mgl_match:(NSExpression *)firstCase, ... {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Match expressions lack underlying Objective-C implementations."];
+ return nil;
+}
+
@end
diff --git a/platform/darwin/src/NSString+MGLAdditions.m b/platform/darwin/src/NSString+MGLAdditions.m
index 8c9bbe3e21..a61f229511 100644
--- a/platform/darwin/src/NSString+MGLAdditions.m
+++ b/platform/darwin/src/NSString+MGLAdditions.m
@@ -1,5 +1,9 @@
#import "NSString+MGLAdditions.h"
+#if TARGET_OS_OSX
+ #import <Availability.h>
+#endif
+
@implementation NSString (MGLAdditions)
- (NSRange)mgl_wholeRange {
@@ -13,7 +17,7 @@
- (NSString *)mgl_titleCasedStringWithLocale:(NSLocale *)locale {
NSMutableString *string = self.mutableCopy;
NSOrthography *orthography;
-#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
if ([NSOrthography respondsToSelector:@selector(defaultOrthographyForLanguage:)]) {
diff --git a/platform/darwin/src/NSValue+MGLAdditions.h b/platform/darwin/src/NSValue+MGLAdditions.h
index f3026a389f..9222f04620 100644
--- a/platform/darwin/src/NSValue+MGLAdditions.h
+++ b/platform/darwin/src/NSValue+MGLAdditions.h
@@ -29,6 +29,19 @@ NS_ASSUME_NONNULL_BEGIN
@property (readonly) CLLocationCoordinate2D MGLCoordinateValue;
/**
+ Creates a new value object containing the specified Mapbox map point structure.
+
+ @param point The value for the new object.
+ @return A new value object that contains the coordinate and zoom level information.
+ */
++ (instancetype)valueWithMGLMapPoint:(MGLMapPoint)point;
+
+/**
+ The Mapbox map point structure representation of the value.
+ */
+@property (readonly) MGLMapPoint MGLMapPointValue;
+
+/**
Creates a new value object containing the specified Mapbox coordinate span
structure.
diff --git a/platform/darwin/src/NSValue+MGLAdditions.m b/platform/darwin/src/NSValue+MGLAdditions.m
index 1383056944..b32445dab7 100644
--- a/platform/darwin/src/NSValue+MGLAdditions.m
+++ b/platform/darwin/src/NSValue+MGLAdditions.m
@@ -14,6 +14,16 @@
return coordinate;
}
++ (instancetype)valueWithMGLMapPoint:(MGLMapPoint)point {
+ return [self valueWithBytes:&point objCType:@encode(MGLMapPoint)];
+}
+
+-(MGLMapPoint) MGLMapPointValue {
+ MGLMapPoint point;
+ [self getValue:&point];
+ return point;
+}
+
+ (instancetype)valueWithMGLCoordinateSpan:(MGLCoordinateSpan)span {
return [self valueWithBytes:&span objCType:@encode(MGLCoordinateSpan)];
}