summaryrefslogtreecommitdiff
path: root/platform/darwin
diff options
context:
space:
mode:
Diffstat (limited to 'platform/darwin')
-rw-r--r--platform/darwin/.gitignore3
-rw-r--r--platform/darwin/docs/guides/For Style Authors.md.ejs153
-rw-r--r--platform/darwin/docs/guides/Migrating to Expressions.md.ejs212
-rw-r--r--platform/darwin/docs/guides/Predicates and Expressions.md889
-rw-r--r--platform/darwin/docs/guides/Tile URL Templates.md.ejs14
-rw-r--r--platform/darwin/docs/guides/Using Style Functions at Runtime.md.ejs99
-rw-r--r--platform/darwin/docs/img/data-driven-styling/cast.pngbin0 -> 49974 bytes
-rw-r--r--platform/darwin/docs/img/data-driven-styling/categorical1.pngbin105968 -> 0 bytes
-rw-r--r--platform/darwin/docs/img/data-driven-styling/categorical2.pngbin125698 -> 0 bytes
-rw-r--r--platform/darwin/docs/img/data-driven-styling/citibikes.pngbin152843 -> 0 bytes
-rw-r--r--platform/darwin/docs/img/data-driven-styling/exponential-function-1.pngbin69991 -> 34835 bytes
-rw-r--r--platform/darwin/docs/img/data-driven-styling/exponential-function.pngbin70066 -> 34933 bytes
-rw-r--r--platform/darwin/docs/img/data-driven-styling/exponential.pngbin86910 -> 0 bytes
-rw-r--r--platform/darwin/docs/img/data-driven-styling/identity.pngbin68837 -> 70278 bytes
-rw-r--r--platform/darwin/docs/img/data-driven-styling/interval.pngbin83927 -> 0 bytes
-rw-r--r--platform/darwin/docs/img/data-driven-styling/multiply.pngbin0 -> 50375 bytes
-rw-r--r--platform/darwin/docs/img/data-driven-styling/polylineExample.pngbin156800 -> 0 bytes
-rw-r--r--platform/darwin/docs/theme/assets/css/jazzy.css.scss7
-rw-r--r--platform/darwin/mbgl/gl/gl_impl.hpp16
-rw-r--r--platform/darwin/mbgl/util/image+MGLAdditions.hpp2
-rw-r--r--platform/darwin/resources/ca.lproj/Foundation.stringsbin13170 -> 6598 bytes
-rw-r--r--platform/darwin/resources/da.lproj/Foundation.strings297
-rw-r--r--platform/darwin/resources/da.lproj/Foundation.stringsdict54
-rw-r--r--platform/darwin/resources/de.lproj/Foundation.stringsbin13082 -> 6575 bytes
-rw-r--r--platform/darwin/resources/fr.lproj/Foundation.stringsbin13222 -> 6625 bytes
-rw-r--r--platform/darwin/resources/he.lproj/Foundation.strings297
-rw-r--r--platform/darwin/resources/ja.lproj/Foundation.stringsbin12488 -> 6691 bytes
-rw-r--r--platform/darwin/resources/lt.lproj/Foundation.stringsbin13652 -> 6954 bytes
-rw-r--r--platform/darwin/resources/pt-BR.lproj/Foundation.stringsbin13274 -> 6656 bytes
-rw-r--r--platform/darwin/resources/pt-PT.lproj/Foundation.stringsdict54
-rw-r--r--platform/darwin/resources/ru.lproj/Foundation.stringsbin13398 -> 7308 bytes
-rw-r--r--platform/darwin/resources/sv.lproj/Foundation.stringsbin13138 -> 6598 bytes
-rw-r--r--platform/darwin/resources/uk.lproj/Foundation.stringsbin13904 -> 7762 bytes
-rw-r--r--platform/darwin/resources/zh-Hans.lproj/Foundation.stringsbin12528 -> 6751 bytes
-rw-r--r--platform/darwin/resources/zh-Hant.lproj/Foundation.stringsbin12496 -> 6703 bytes
-rwxr-xr-x[-rw-r--r--]platform/darwin/scripts/generate-style-code.js232
-rw-r--r--platform/darwin/scripts/style-spec-overrides-v8.json31
-rwxr-xr-x[-rw-r--r--]platform/darwin/scripts/update-examples.js12
-rw-r--r--platform/darwin/src/MGLAccountManager.h26
-rw-r--r--platform/darwin/src/MGLAccountManager.m11
-rw-r--r--platform/darwin/src/MGLAccountManager_Private.h2
-rw-r--r--platform/darwin/src/MGLAttributionInfo.mm14
-rw-r--r--platform/darwin/src/MGLAttributionInfo_Private.h6
-rw-r--r--platform/darwin/src/MGLBackgroundStyleLayer.h74
-rw-r--r--platform/darwin/src/MGLBackgroundStyleLayer.mm31
-rw-r--r--platform/darwin/src/MGLCircleStyleLayer.h408
-rw-r--r--platform/darwin/src/MGLCircleStyleLayer.mm122
-rw-r--r--platform/darwin/src/MGLCompassDirectionFormatter.m4
-rw-r--r--platform/darwin/src/MGLComputedShapeSource.h165
-rw-r--r--platform/darwin/src/MGLComputedShapeSource.mm225
-rw-r--r--platform/darwin/src/MGLComputedShapeSource_Private.h12
-rw-r--r--platform/darwin/src/MGLConversion.h227
-rw-r--r--platform/darwin/src/MGLFeature.h35
-rw-r--r--platform/darwin/src/MGLFeature.mm14
-rw-r--r--platform/darwin/src/MGLFeature_Private.h4
-rw-r--r--platform/darwin/src/MGLFillExtrusionStyleLayer.h234
-rw-r--r--platform/darwin/src/MGLFillExtrusionStyleLayer.mm79
-rw-r--r--platform/darwin/src/MGLFillStyleLayer.h268
-rw-r--r--platform/darwin/src/MGLFillStyleLayer.mm83
-rw-r--r--platform/darwin/src/MGLForegroundStyleLayer.h9
-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.h215
-rw-r--r--platform/darwin/src/MGLHeatmapStyleLayer.mm210
-rw-r--r--platform/darwin/src/MGLHillshadeStyleLayer.h324
-rw-r--r--platform/darwin/src/MGLHillshadeStyleLayer.mm239
-rw-r--r--platform/darwin/src/MGLLight.h101
-rw-r--r--platform/darwin/src/MGLLight.h.ejs6
-rw-r--r--platform/darwin/src/MGLLight.mm28
-rw-r--r--platform/darwin/src/MGLLight.mm.ejs16
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.h461
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.mm153
-rw-r--r--platform/darwin/src/MGLMapSnapshotter.h2
-rw-r--r--platform/darwin/src/MGLMapSnapshotter.mm3
-rw-r--r--platform/darwin/src/MGLMultiPoint.mm2
-rw-r--r--platform/darwin/src/MGLNetworkConfiguration.h8
-rw-r--r--platform/darwin/src/MGLNetworkConfiguration.m5
-rw-r--r--platform/darwin/src/MGLOfflineStorage.h12
-rw-r--r--platform/darwin/src/MGLOfflineStorage.mm12
-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+MGLAdditions.h7
-rw-r--r--platform/darwin/src/MGLPolygon+MGLAdditions.m27
-rw-r--r--platform/darwin/src/MGLPolygon.h17
-rw-r--r--platform/darwin/src/MGLPolygon.mm32
-rw-r--r--platform/darwin/src/MGLPolygon_Private.h11
-rw-r--r--platform/darwin/src/MGLPolyline+MGLAdditions.h7
-rw-r--r--platform/darwin/src/MGLPolyline+MGLAdditions.m14
-rw-r--r--platform/darwin/src/MGLPolyline.h13
-rw-r--r--platform/darwin/src/MGLPolyline.mm27
-rw-r--r--platform/darwin/src/MGLPolyline_Private.h12
-rw-r--r--platform/darwin/src/MGLRasterDEMSource.h50
-rw-r--r--platform/darwin/src/MGLRasterDEMSource.mm17
-rw-r--r--platform/darwin/src/MGLRasterSource_Private.h8
-rw-r--r--platform/darwin/src/MGLRasterStyleLayer.h178
-rw-r--r--platform/darwin/src/MGLRasterStyleLayer.mm100
-rw-r--r--platform/darwin/src/MGLRasterTileSource.h (renamed from platform/darwin/src/MGLRasterSource.h)47
-rw-r--r--platform/darwin/src/MGLRasterTileSource.mm (renamed from platform/darwin/src/MGLRasterSource.mm)27
-rw-r--r--platform/darwin/src/MGLRasterTileSource_Private.h21
-rw-r--r--platform/darwin/src/MGLRendererConfiguration.h4
-rw-r--r--platform/darwin/src/MGLRendererFrontend.h4
-rw-r--r--platform/darwin/src/MGLShape.h18
-rw-r--r--platform/darwin/src/MGLShapeCollection.h9
-rw-r--r--platform/darwin/src/MGLShapeCollection.mm4
-rw-r--r--platform/darwin/src/MGLShapeSource.h92
-rw-r--r--platform/darwin/src/MGLShapeSource.mm133
-rw-r--r--platform/darwin/src/MGLShapeSource_Private.h5
-rw-r--r--platform/darwin/src/MGLSource.h9
-rw-r--r--platform/darwin/src/MGLStyle.h113
-rw-r--r--platform/darwin/src/MGLStyle.mm263
-rw-r--r--platform/darwin/src/MGLStyleLayer.h.ejs13
-rw-r--r--platform/darwin/src/MGLStyleLayer.mm.ejs80
-rw-r--r--platform/darwin/src/MGLStyleValue.h470
-rw-r--r--platform/darwin/src/MGLStyleValue.mm334
-rw-r--r--platform/darwin/src/MGLStyleValue_Private.h640
-rw-r--r--platform/darwin/src/MGLStyle_Private.h12
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.h1665
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.mm586
-rw-r--r--platform/darwin/src/MGLTileSource.h38
-rw-r--r--platform/darwin/src/MGLTileSource.mm25
-rw-r--r--platform/darwin/src/MGLTileSource_Private.h4
-rw-r--r--platform/darwin/src/MGLTypes.h20
-rw-r--r--platform/darwin/src/MGLVectorSource+MGLAdditions.h15
-rw-r--r--platform/darwin/src/MGLVectorSource+MGLAdditions.m53
-rw-r--r--platform/darwin/src/MGLVectorSource.mm73
-rw-r--r--platform/darwin/src/MGLVectorSource_Private.h8
-rw-r--r--platform/darwin/src/MGLVectorStyleLayer.h117
-rw-r--r--platform/darwin/src/MGLVectorTileSource.h (renamed from platform/darwin/src/MGLVectorSource.h)45
-rw-r--r--platform/darwin/src/MGLVectorTileSource.mm153
-rw-r--r--platform/darwin/src/MGLVectorTileSource_Private.h18
-rw-r--r--platform/darwin/src/NSArray+MGLAdditions.mm2
-rw-r--r--platform/darwin/src/NSBundle+MGLAdditions.h2
-rw-r--r--platform/darwin/src/NSBundle+MGLAdditions.m2
-rw-r--r--platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm298
-rw-r--r--platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm62
-rw-r--r--platform/darwin/src/NSDictionary+MGLAdditions.mm2
-rw-r--r--platform/darwin/src/NSExpression+MGLAdditions.h197
-rw-r--r--platform/darwin/src/NSExpression+MGLAdditions.mm1317
-rw-r--r--platform/darwin/src/NSExpression+MGLPrivateAdditions.h89
-rw-r--r--platform/darwin/src/NSPredicate+MGLAdditions.h14
-rw-r--r--platform/darwin/src/NSPredicate+MGLAdditions.mm192
-rw-r--r--platform/darwin/src/NSString+MGLAdditions.h11
-rw-r--r--platform/darwin/src/NSString+MGLAdditions.m26
-rw-r--r--platform/darwin/src/NSValue+MGLAdditions.h13
-rw-r--r--platform/darwin/src/NSValue+MGLAdditions.m10
-rw-r--r--platform/darwin/src/headless_backend_cgl.cpp132
-rw-r--r--platform/darwin/src/headless_backend_eagl.mm52
-rw-r--r--platform/darwin/src/headless_display_cgl.cpp60
-rw-r--r--platform/darwin/src/image.mm2
-rw-r--r--platform/darwin/src/run_loop.cpp7
-rw-r--r--platform/darwin/test/MGLAttributionInfoTests.m10
-rw-r--r--platform/darwin/test/MGLBackgroundStyleLayerTests.mm129
-rw-r--r--platform/darwin/test/MGLCircleStyleLayerTests.mm568
-rw-r--r--platform/darwin/test/MGLComputedShapeSourceTests.m24
-rw-r--r--platform/darwin/test/MGLDocumentationExampleTests.swift157
-rw-r--r--platform/darwin/test/MGLDocumentationGuideTests.swift242
-rw-r--r--platform/darwin/test/MGLExpressionTests.mm955
-rw-r--r--platform/darwin/test/MGLFeatureTests.mm33
-rw-r--r--platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm344
-rw-r--r--platform/darwin/test/MGLFillStyleLayerTests.mm344
-rw-r--r--platform/darwin/test/MGLGeometryTests.mm9
-rw-r--r--platform/darwin/test/MGLHeatmapColorTests.mm62
-rw-r--r--platform/darwin/test/MGLHeatmapStyleLayerTests.mm300
-rw-r--r--platform/darwin/test/MGLHillshadeStyleLayerTests.mm348
-rw-r--r--platform/darwin/test/MGLLightTest.mm49
-rw-r--r--platform/darwin/test/MGLLightTest.mm.ejs17
-rw-r--r--platform/darwin/test/MGLLineStyleLayerTests.mm675
-rw-r--r--platform/darwin/test/MGLNSStringAdditionsTests.m26
-rw-r--r--platform/darwin/test/MGLPredicateTests.mm696
-rw-r--r--platform/darwin/test/MGLRasterStyleLayerTests.mm310
-rw-r--r--platform/darwin/test/MGLSDKTestHelpers.swift18
-rw-r--r--platform/darwin/test/MGLShapeSourceTests.mm3
-rw-r--r--platform/darwin/test/MGLSourceQueryTests.m4
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.h5
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.m4
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.mm.ejs73
-rw-r--r--platform/darwin/test/MGLStyleTests.mm154
-rw-r--r--platform/darwin/test/MGLStyleValueTests.h4
-rw-r--r--platform/darwin/test/MGLStyleValueTests.m113
-rw-r--r--platform/darwin/test/MGLStyleValueTests.swift362
-rw-r--r--platform/darwin/test/MGLSymbolStyleLayerTests.mm2332
-rw-r--r--platform/darwin/test/MGLTileSetTests.mm29
-rw-r--r--platform/darwin/test/test-Bridging-Header.h2
186 files changed, 14285 insertions, 8621 deletions
diff --git a/platform/darwin/.gitignore b/platform/darwin/.gitignore
new file mode 100644
index 0000000000..f4635b2c19
--- /dev/null
+++ b/platform/darwin/.gitignore
@@ -0,0 +1,3 @@
+# Generated list files from code generation
+/scripts/generate-style-code.list
+/scripts/update-examples.list
diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs
index ba6f14647c..2ae6602224 100644
--- a/platform/darwin/docs/guides/For Style Authors.md.ejs
+++ b/platform/darwin/docs/guides/For Style Authors.md.ejs
@@ -178,21 +178,22 @@ source object is a member of one of the following subclasses of `MGLSource`:
In style JSON | In the SDK
--------------|-----------
+`vector` | `MGLVectorTileSource`
+`raster` | `MGLRasterTileSource`
+`raster-dem` | `MGLRasterDEMSource`
`geojson` | `MGLShapeSource`
-`raster` | `MGLRasterSource`
-`vector` | `MGLVectorSource`
`image` | `MGLImageSource`
`canvas` and `video` sources are not supported.
### Tile sources
-Raster and vector sources may be defined in TileJSON configuration files. This
-SDK supports the properties defined in the style specification, which are a
+Raster and vector tile sources may be defined in TileJSON configuration files.
+This SDK supports the properties defined in the style specification, which are a
subset of the keys defined in version 2.1.0 of the
[TileJSON](https://github.com/mapbox/tilejson-spec/tree/master/2.1.0)
specification. As an alternative to authoring a custom TileJSON file, you may
-supply various tile source options when creating a raster or vector source.
+supply various tile source options when creating a raster or vector tile source.
These options are detailed in the `MGLTileSourceOption` documentation:
In style JSON | In TileJSON | In the SDK
@@ -205,6 +206,7 @@ In style JSON | In TileJSON | In the SDK
`tileSize` | — | `MGLTileSourceOptionTileSize`
`attribution` | `attribution` | `MGLTileSourceOptionAttributionHTMLString` (but consider specifying `MGLTileSourceOptionAttributionInfos` instead for improved security)
`scheme` | `scheme` | `MGLTileSourceOptionTileCoordinateSystem`
+`encoding` | – | `MGLTileSourceOptionDEMEncoding`
### Shape sources
@@ -265,12 +267,16 @@ In style JSON | In Objective-C | In Swift
## Setting attribute values
Each property representing a layout or paint attribute is set to an
-`MGLStyleValue` object, which is either an `MGLConstantStyleValue` object (for
-constant values) or an `MGLStyleFunction` object (for style functions). The
-style value object is a container for the raw value or function parameters that
-you want the attribute to be set to.
+`NSExpression` object. `NSExpression` objects play the same role as
+[expressions in the Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions),
+but you create the former using a very different syntax. `NSExpression`’s format
+string syntax is reminiscent of a spreadsheet formula or an expression in a
+database query. See the
+“[Predicates and Expressions](Predicates and Expressions.md)” guide for an
+overview of the expression support in this SDK. This SDK no longer supports
+style functions; use expressions instead.
-### Constant style values
+### Constant values in expressions
In contrast to the JSON type that the style specification defines for each
layout or paint property, the style value object often contains a more specific
@@ -281,10 +287,10 @@ or set.
In style JSON | In Objective-C | In Swift
--------------|-----------------------|---------
Color | `<%- cocoaPrefix %>Color` | `<%- cocoaPrefix %>Color`
-Enum | `NSValue` (see `NSValue(MGLAdditions)`) | `NSValue` (see `NSValue(MGLAdditions)`)
+Enum | `NSString` | `String`
String | `NSString` | `String`
-Boolean | `NSNumber.boolValue` | `Bool`
-Number | `NSNumber.floatValue` | `Float`
+Boolean | `NSNumber.boolValue` | `NSNumber.boolValue`
+Number | `NSNumber.floatValue` | `NSNumber.floatValue`
Array (`-dasharray`) | `NSArray<NSNumber>` | `[Float]`
Array (`-font`) | `NSArray<NSString>` | `[String]`
<% if (iOS) { -%>
@@ -314,42 +320,93 @@ translation downward. This is the reverse of how `CGVector` is interpreted on
iOS.
<% } -%>
-### Style functions
-
-A _style function_ allows you to vary the value of a layout or paint attribute
-based on the zoom level, data provided by content sources, or both. For more
-information about style functions, see “[Using Style Functions at Runtime](using-style-functions-at-runtime.html)”.
-
-Each kind of style function is represented by a distinct class, but you
-typically create style functions as you create any other style value, using
-class methods on `MGLStyleValue`:
-
-In style specification | SDK class | SDK factory method
----------------------------|-----------------------------|-------------------
-zoom function | `MGLCameraStyleFunction` | `+[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]`
-property function | `MGLSourceStyleFunction` | `+[MGLStyleValue valueWithInterpolationMode:sourceStops:attributeName:options:]`
-zoom-and-property function | `MGLCompositeStyleFunction` | `+[MGLStyleValue valueWithInterpolationMode:compositeStops:attributeName:options:]`
-
-The documentation for each individual style layer property indicates the kinds
-of style functions that are enabled for that property.
-
-When you create a style function, you specify an _interpolation mode_ and a
-series of _stops_. Each stop determines the effective value displayed at a
-particular zoom level (for camera functions) or the effective value on features
-with a particular attribute value in the content source (for source functions).
-The interpolation mode tells the SDK how to calculate the effective value
-between any two stops:
-
-In style specification | In the SDK
------------------------------|-----------
-`exponential` | `MGLInterpolationModeExponential`
-`interval` | `MGLInterpolationModeInterval`
-`categorical` | `MGLInterpolationModeCategorical`
-`identity` | `MGLInterpolationModeIdentity`
+### Expression operators
+
+Many expression operators defined in the style specification have corresponding
+symbols to be used with the `+[NSExpression expressionWithFormat:]`,
+`+[NSExpression expressionForFunction:arguments:]`, or
+`+[NSExpression expressionForFunction:selectorName:arguments:]` method:
+
+In style specification | Method, function, or predicate type | Format string syntax
+-----------------------|-------------------------------------|---------------------
+`array` | |
+`boolean` | |
+`literal` | `+[NSExpression expressionForConstantValue:]` | `%@` representing `NSArray` or `NSDictionary`
+`number` | |
+`string` | |
+`to-boolean` | `boolValue` |
+`to-color` | |
+`to-number` | `mgl_numberWithFallbackValues:` | `CAST(zipCode, 'NSNumber')`
+`to-string` | `stringValue` | `CAST(ele, 'NSString')`
+`typeof` | |
+`geometry-type` | `NSExpression.geometryTypeVariableExpression` | `$geometryType`
+`id` | `NSExpression.featureIdentifierVariableExpression` | `$featureIdentifier`
+`properties` | `NSExpression.featureAttributesVariableExpression` | `$featureAttributes`
+`at` | `objectFrom:withIndex:` | `array[n]`
+`get` | `+[NSExpression expressionForKeyPath:]` | Key path
+`has` | `mgl_does:have:` | `mgl_does:have:(self, 'key')`
+`length` | `count:` | `count({1, 2, 2, 3, 4, 7, 9})`
+`!` | `NSNotPredicateType` | `NOT (p0 OR … OR pn)`
+`!=` | `NSNotEqualToPredicateOperatorType` | `key != value`
+`<` | `NSLessThanPredicateOperatorType` | `key < value`
+`<=` | `NSLessThanOrEqualToPredicateOperatorType` | `key <= value`
+`==` | `NSEqualToPredicateOperatorType` | `key == value`
+`>` | `NSGreaterThanPredicateOperatorType` | `key > value`
+`>=` | `NSGreaterThanOrEqualToPredicateOperatorType` | `key >= value`
+`all` | `NSAndPredicateType` | `p0 AND … AND pn`
+`any` | `NSOrPredicateType` | `p0 OR … OR pn`
+`case` | `+[NSExpression expressionForConditional:trueExpression:falseExpression:]` or `MGL_IF` or `+[NSExpression mgl_expressionForConditional:trueExpression:falseExpresssion:]` | `TERNARY(1 = 2, YES, NO)` or `MGL_IF(1 = 2, YES, 2 = 2, YES, NO)`
+`coalesce` | `mgl_coalesce:` | `mgl_coalesce({x, y, z})`
+`match` | `MGL_MATCH` or `+[NSExpression mgl_expressionForMatchingExpression:inDictionary:defaultExpression:]` | `MGL_MATCH(x, 0, 'zero match', 1, 'one match', 'two match', 'default')`
+`interpolate` | `mgl_interpolate:withCurveType:parameters:stops:` or `+[NSExpression mgl_expressionForInterpolatingExpression:withCurveType:parameters:stops:]` |
+`step` | `mgl_step:withMinimum:stops:` or `+[NSExpression mgl_expressionForSteppingExpression:fromExpression:stops:]` |
+`let` | `mgl_expressionWithContext:` | `MGL_LET('ios', 11, 'macos', 10.13, $ios + $macos)`
+`var` | `+[NSExpression expressionForVariable:]` | `$variable`
+`concat` | `mgl_join:` or `-[NSExpression mgl_expressionByAppendingExpression:]` | `mgl_join({'Old', ' ', 'MacDonald'})`
+`downcase` | `lowercase:` | `lowercase('DOWNTOWN')`
+`upcase` | `uppercase:` | `uppercase('Elysian Fields')`
+<% if (macOS) { -%>
+`rgb` | `+[NSColor colorWithCalibratedRed:green:blue:alpha:]` |
+`rgba` | `+[NSColor colorWithCalibratedRed:green:blue:alpha:]` |
+<% } else { -%>
+`rgb` | `+[UIColor colorWithRed:green:blue:alpha:]` |
+`rgba` | `+[UIColor colorWithRed:green:blue:alpha:]` |
+<% } -%>
+`to-rgba` | |
+`-` | `from:subtract:` | `2 - 1`
+`*` | `multiply:by:` | `1 * 2`
+`/` | `divide:by:` | `1 / 2`
+`%` | `modulus:by:` |
+`^` | `raise:toPower:` | `2 ** 2`
+`+` | `add:to:` | `1 + 2`
+`abs` | `abs:` | `abs(-1)`
+`acos` | `mgl_acos:` | `mgl_acos(1)`
+`asin` | `mgl_asin:` | `mgl_asin(0)`
+`atan` | `mgl_atan:` | `mgl_atan(20)`
+`ceil` | `ceiling:` | `ceiling(0.99999)`
+`cos` | `mgl_cos:` | `mgl_cos(0)`
+`e` | | `%@` representing `NSNumber` containing `M_E`
+`floor` | `floor:` | `floor(-0.99999)`
+`ln` | `ln:` | `ln(2)`
+`ln2` | | `%@` representing `NSNumber` containing `M_LN2`
+`log10` | `log:` | `log(1)`
+`log2` | `mgl_log2:` | `mgl_log2(1024)`
+`max` | `max:` | `max({1, 2, 2, 3, 4, 7, 9})`
+`min` | `min:` | `min({1, 2, 2, 3, 4, 7, 9})`
+`pi` | | `%@` representing `NSNumber` containing `M_PI`
+`round` | `mgl_round:` | `mgl_round(1.5)`
+`sin` | `mgl_sin:` | `mgl_sin(0)`
+`sqrt` | `sqrt:` | `sqrt(2)`
+`tan` | `mgl_tan:` | `mgl_tan(0)`
+`zoom` | `NSExpression.zoomLevelVariableExpression` | `$zoom`
+`heatmap-density` | `NSExpression.heatmapDensityVariableExpression` | `$heatmapDensity`
+
+For operators that have no corresponding `NSExpression` symbol, use the
+`MGL_FUNCTION()` format string syntax.
## Filtering sources
-You can filter a shape or vector source by setting the
+You can filter a shape or vector tile source by setting the
`MGLVectorStyleLayer.predicate` property to an `NSPredicate` object. Below is a
table of style JSON operators and the corresponding operators used in the
predicate format string:
@@ -370,5 +427,5 @@ In style JSON | In the format string
`["any", f0, …, fn]` | `p0 OR … OR pn`
`["none", f0, …, fn]` | `NOT (p0 OR … OR pn)`
-See the `MGLVectorStyleLayer.predicate` documentation for a full description of
-the supported operators and operand types.
+See the “[Predicates and Expressions](Predicates and Expressions.md)” guide for
+a full description of the supported operators and operand types.
diff --git a/platform/darwin/docs/guides/Migrating to Expressions.md.ejs b/platform/darwin/docs/guides/Migrating to Expressions.md.ejs
new file mode 100644
index 0000000000..addbf6940e
--- /dev/null
+++ b/platform/darwin/docs/guides/Migrating to Expressions.md.ejs
@@ -0,0 +1,212 @@
+<%
+ const os = locals.os;
+ const iOS = os === 'iOS';
+ const macOS = os === 'macOS';
+ const cocoaPrefix = iOS ? 'UI' : 'NS';
+ const guide = 'MigratingToExpressions';
+-%>
+<!--
+ This file is generated.
+ Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
+-->
+
+# Migrating from Style Functions to Expressions
+
+[Runtime Styling](runtime-styling.html) enables you to modify every aspect of the map’s appearance dynamically as a user interacts with your application. Developers can specify in advance how a layout or paint attribute will vary as the zoom level changes or how the appearance of individual features vary based on metadata provided by a content source.
+
+With Mapbox Maps SDK for <%- iOS ? 'iOS v4.0.0' : 'macOS v0.7.0' %>, style functions have been replaced with expressions. These provide even more tools for developers who want to style their maps dynamically. This guide outlines some tips for migrating from style functions to expressions, and offers an overview of some things that developers can do with expressions.
+
+An expression is represented at runtime by the `NSExpression` class. Expressions can be used to style paint and layout properties based on zoom level, data attributes, or a combination of the two.
+
+A constant expression can also be assigned to a style property. For example, the opacity of a fill style layer can be set to a constant value between 0 and 1.
+
+The documentation for each individual style layer property notes which non-constant expressions are enabled for that property. Style functions supported four interpolation modes: exponential, interval, categorical, and identity.
+
+This guide uses earthquake data from the [U.S. Geological Survey](https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php). Under each interpolation mode, the style function implementation will be shown, followed by the current syntax.
+
+For more information about how to work with GeoJSON data in our <%- os %> SDK, please see our [working with GeoJSON data](working-with-geojson-data.html) guide. To learn more about supported expressions, see our ["Predicates and Expressions"](predicates-and-expressions.html) guide. The "Predicates and Expressions" guide also outlines Mapbox custom functions that can be used to dynamically style a map.
+
+## Stops
+Stops are dictionary keys that are associated with layer attribute values. Constant values no longer need to be wrapped as style values when they are values in a stops dictionary.
+
+
+Style function syntax:
+
+```swift
+let stops = [
+ 0: MGLStyleValue<UIColor>(rawValue: .yellow),
+ 2.5: MGLStyleValue(rawValue: .orange),
+ 5: MGLStyleValue(rawValue: .red),
+ 7.5: MGLStyleValue(rawValue: .blue),
+ 10: MGLStyleValue(rawValue: .white),
+]
+```
+
+Current syntax:
+<%- guideExample(guide, 'Stops', os) %>
+
+
+## Interpolation mode
+
+Style functions supported four interpolation modes: exponential/linear, interval, categorical, and identity. For more information about supported custom expressions, please see the "Predicates and Expressions" guide.
+
+### Linear
+
+`+[NSExpression(MGLAdditions) mgl_expressionForInterpolatingExpression:withCurveType:parameters:stops:]` takes the interpolation type as a parameter. If you previously used the default interpolation base, use the curve type `MGLExpressionInterpolationMode.linear`. See the [`mgl_interpolate:withCurveType:parameters:stops:`](predicates-and-expressions.html#code-mgl_interpolate-withcurvetype-parameters-stops-code) documentation for more details.
+
+The stops dictionary below, shows colors that continuously shift from yellow to orange to red to blue to white based on the attribute value.
+
+Style function syntax:
+
+```swift
+let url = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson")!
+let symbolSource = MGLSource(identifier: "source")
+let symbolLayer = MGLSymbolStyleLayer(identifier: "place-city-sm", source: symbolSource)
+
+let source = MGLShapeSource(identifier: "earthquakes", url: url, options: nil)
+mapView.style?.addSource(source)
+
+let stops = [
+ 0: MGLStyleValue<UIColor>(rawValue: .yellow),
+ 2.5: MGLStyleValue(rawValue: .orange),
+ 5: MGLStyleValue(rawValue: .red),
+ 7.5: MGLStyleValue(rawValue: .blue),
+ 10: MGLStyleValue(rawValue: .white),
+]
+
+let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
+layer.circleColor = MGLStyleValue(interpolationMode: .exponential,
+ sourceStops: stops,
+ attributeName: "mag",
+ options: [.defaultValue: MGLStyleValue<UIColor>(rawValue: .green)])
+layer.circleRadius = MGLStyleValue(rawValue: 10)
+mapView.style?.insertLayer(layer, below: symbolLayer)
+```
+
+Current syntax:
+
+<%- guideExample(guide, 'Linear', os) %>
+
+### Exponential
+
+If you previously used an interpolation base greater than `0` (other than `1`), you can use `MGLExpressionInterpolationMode.exponential` as the curve type for `+[NSExpression(MGLAdditions) mgl_expressionForInterpolatingExpression:withCurveType:parameters:stops:]` or `'exponential'` as the curve type for [`mgl_interpolate:withCurveType:parameters:stops:`](predicates-and-expressions.html#code-mgl_interpolate-withcurvetype-parameters-stops-code). The `parameters` argument takes that interpolation base. This interpolates between values exponentially, creating an accelerated ramp effect.
+
+Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](working-with-mapbox-studio.html)) comparing interpolation base values of `1.5` and `0.5` based on zoom. In order to convert camera style functions, use `$zoomLevel` or `MGL_FUNCTION('zoomLevel')` as the attribute key.
+
+<img src="img/data-driven-styling/exponential-function.png" height=344/>
+<img src="img/data-driven-styling/exponential-function-1.png" height=344/>
+
+The example below increases a layer’s `circleRadius` exponentially based on a map’s zoom level. The interpolation base is `1.5`.
+
+Style function syntax:
+
+```swift
+let stops = [
+ 12: MGLStyleValue<NSNumber>(rawValue: 0.5),
+ 14: MGLStyleValue(rawValue: 2),
+ 18: MGLStyleValue(rawValue: 18),
+]
+
+layer.circleRadius = MGLStyleValue(interpolationMode: .exponential,
+ cameraStops: stops,
+ options: [.interpolationBase: 1.5])
+```
+
+Current syntax:
+
+<%- guideExample(guide, 'Exponential', os) %>
+
+### Interval
+
+Steps, or intervals, create a range using the keys from the stops dictionary. The range is from the given key to just less than the next key. The attribute values that fall into that range are then styled using the layout or paint value assigned to that key. You can use the `+[NSExpression(MGLAdditions) mgl_expressionForSteppingExpression:fromExpression:stops:]` method or the custom function [`mgl_step:from:stops:`](predicates-and-expressions.html#code-mgl_step-from-stops-code) for cases where you previously used interval interpolation mode. The first parameter takes the feature attribute name and the second parameter (`from:`) optionally takes the default or fallback value for that function. The final parameter takes a stops dictionary as an argument.
+
+When we use the stops dictionary given above with an `'mgl_step:from:stops:'`, we create ranges where earthquakes with a magnitude of 0 to just less than 2.5 would be yellow, 2.5 to just less than 5 would be orange, and so on.
+
+Style function syntax:
+
+```swift
+let stops = [
+ 0: MGLStyleValue<UIColor>(rawValue: .yellow),
+ 2.5: MGLStyleValue(rawValue: .orange),
+ 5: MGLStyleValue(rawValue: .red),
+ 7.5: MGLStyleValue(rawValue: .blue),
+ 10: MGLStyleValue(rawValue: .white),
+]
+
+layer.circleColor = MGLStyleValue(interpolationMode: .interval,
+ sourceStops: stops,
+ attributeName: "mag",
+ options: [.defaultValue: MGLStyleValue<UIColor>(rawValue: .green)])
+````
+
+Current syntax:
+
+<%- guideExample(guide, 'Interval', os) %>
+
+### Categorical
+
+Categorical interpolation mode took a stops dictionary. If the value for a specified feature attribute name matched one in that stops dictionary, the style value for that attribute value would be used. Categorical style functions can now be replaced with `MGL_MATCH`.
+
+`MGL_MATCH` takes an initial condition, which in this case is an attribute key. This is followed by possible matches for that key and the value to assign to the layer property if there is a match. The final argument can be a default style value that is to be used if none of the specified values match.
+
+There are three main types of events in the USGS dataset: earthquakes, explosions, and quarry blasts. In this case, the color of the circle layer will be determined by the type of event, with a default value of blue to catch any events that do not fall into any of those categories.
+
+Style function syntax:
+
+```swift
+let categoricalStops = [
+ "earthquake": MGLStyleValue<UIColor>(rawValue: .orange),
+ "explosion": MGLStyleValue(rawValue: .red),
+ "quarry blast": MGLStyleValue(rawValue: .yellow),
+]
+
+layer.circleColor = MGLStyleValue(interpolationMode: .categorical,
+ sourceStops: categoricalStops,
+ attributeName: "type",
+ options: [.defaultValue: MGLStyleValue<UIColor>(rawValue: .blue)])
+```
+
+Current syntax:
+<%- guideExample(guide, 'Categorical', os) %>
+
+If your use case does not require a default value, you can either apply a predicate to your layer prior to styling it, or use the format string `"valueForKeyPath:"`.
+
+### Identity
+
+Identity interpolation mode used the attribute’s value as the style layer property value. In this example, you might set the `circleRadius` to the earthquake’s magnitude. In order to use a feature attribute value to style a layer property, set the property value to `[NSExpression expressionForKeyPath:]`, which take the feature attribute name as an argument.
+
+Style function syntax:
+
+```swift
+layer.circleRadius = MGLStyleValue(interpolationMode: .identity,
+ sourceStops: nil,
+ attributeName: "mag",
+ options: [.defaultValue: MGLStyleValue<NSNumber>(rawValue: 0)])
+```
+
+Current syntax:
+<%- guideExample(guide, 'Identity', os) %>
+
+![identity mode](img/data-driven-styling/identity.png)
+
+Some built-in functions can be applied to attribute values to style layer property values. To set the circle radius to three times the earthquake’s magnitude, create a `multiply:by:` function that takes the attribute value and the multiplier as arguments, or use a format string.
+
+<%- guideExample(guide, 'Multiply', os) %>
+
+![multiply magnitude](img/data-driven-styling/multiply.png)
+
+You can also cast attribute values in order to use them. One example is to cast an integer as an `NSString` and use it as a text value.
+
+<%- guideExample(guide, 'Cast', os) %>
+
+![cast a value](img/data-driven-styling/cast.png)
+
+### Constant Values
+
+For constant values that do not necessarily change based on camera or attribute values, use `[NSExpression expressionForConstantValue:]` (previously `[MGLStyleValue valueWithRawValue:]`).
+
+## Resources
+
+* [USGS Earthquake Feed](https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php)
+* [For Style Authors](for-style-authors.html)
+* [Predicates and Expressions](predicates-and-expressions.html)
diff --git a/platform/darwin/docs/guides/Predicates and Expressions.md b/platform/darwin/docs/guides/Predicates and Expressions.md
new file mode 100644
index 0000000000..c3b3d39a52
--- /dev/null
+++ b/platform/darwin/docs/guides/Predicates and Expressions.md
@@ -0,0 +1,889 @@
+# Predicates and expressions
+
+Style layers use predicates and expressions to determine what to display and how
+to format it. _Predicates_ are represented by the same `NSPredicate` class that
+filters results from Core Data or items in an `NSArray` in Objective-C.
+Predicates are based on _expressions_, represented by the `NSExpression` class.
+Somewhat unusually, style layers also use expressions on their own.
+
+This document discusses the specific subset of the predicate and expression
+syntax supported by this SDK. For a more general introduction to predicates and
+expressions, consult the
+_[Predicate Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Predicates/AdditionalChapters/Introduction.html)_
+in Apple developer documentation.
+
+## Using predicates to filter vector data
+
+Most style layer classes display `MGLFeature` objects that you can show or hide
+based on the feature’s attributes. Use the `MGLVectorStyleLayer.predicate`
+property to include only the features in the source layer that satisfy a
+condition that you define.
+
+### Operators
+
+The following comparison operators are supported:
+
+`NSPredicateOperatorType` | Format string syntax
+----------------------------------------------|---------------------
+`NSEqualToPredicateOperatorType` | `key = value`<br />`key == value`
+`NSGreaterThanOrEqualToPredicateOperatorType` | `key >= value`<br />`key => value`
+`NSLessThanOrEqualToPredicateOperatorType` | `key <= value`<br />`key =< value`
+`NSGreaterThanPredicateOperatorType` | `key > value`
+`NSLessThanPredicateOperatorType` | `key < value`
+`NSNotEqualToPredicateOperatorType` | `key != value`<br />`key <> value`
+`NSBetweenPredicateOperatorType` | `key BETWEEN { 32, 212 }`
+
+To test whether a feature has or lacks a specific attribute, compare the
+attribute to `NULL` or `NIL`. Predicates created using the
+`+[NSPredicate predicateWithValue:]` method are also supported. String
+operators and custom operators are not supported.
+
+The following compound operators are supported:
+
+`NSCompoundPredicateType` | Format string syntax
+--------------------------|---------------------
+`NSAndPredicateType` | `predicate1 AND predicate2`<br />`predicate1 && predicate2`
+`NSOrPredicateType` | `predicate1 OR predicate2`<br /><code>predicate1 &vert;&vert; predicate2</code>
+`NSNotPredicateType` | `NOT predicate`<br />`!predicate`
+
+The following aggregate operators are supported:
+
+`NSPredicateOperatorType` | Format string syntax
+----------------------------------|---------------------
+`NSInPredicateOperatorType` | `key IN { 'iOS', 'macOS', 'tvOS', 'watchOS' }`
+`NSContainsPredicateOperatorType` | `{ 'iOS', 'macOS', 'tvOS', 'watchOS' } CONTAINS key`
+
+Operator modifiers such as `c` (for case insensitivity), `d` (for diacritic
+insensitivity), and `l` (for locale sensitivity) are unsupported for comparison
+and aggregate operators that are used in the predicate.
+
+### Operands
+
+Operands in predicates can be [variables](#variables), [key paths](#key-paths),
+or almost anything else that can appear
+[inside an expression](#using-expressions-to-configure-layout-and-paint-attributes).
+
+Automatic type casting is not performed. Therefore, a feature only matches a
+predicate if its value for the attribute in question is of the same type as the
+value specified in the predicate. Use the `CAST()` operator to convert a key
+path or variable into a matching type:
+
+* To cast a value to a number, use `CAST(key, 'NSNumber')`.
+* To cast a value to a string, use `CAST(key, 'NSString')`.
+
+For details about the predicate format string syntax, consult the “Predicate
+Format String Syntax” chapter of the
+_[Predicate Programming Guide](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Predicates/AdditionalChapters/Introduction.html)_
+in Apple developer documentation.
+
+## Using expressions to configure layout and paint attributes
+
+An expression can contain subexpressions of various types. Each of the supported
+types of expressions is discussed below.
+
+### Constant values
+
+A constant value can be of any of the following types:
+
+In Objective-C | In Swift
+----------------------|---------
+`NSColor` (macOS)<br>`UIColor` (iOS) | `NSColor` (macOS)<br>`UIColor` (iOS)
+`NSString` | `String`
+`NSString` | `String`
+`NSNumber.boolValue` | `NSNumber.boolValue`
+`NSNumber.doubleValue` | `NSNumber.doubleValue`
+`NSArray<NSNumber>` | `[Float]`
+`NSArray<NSString>` | `[String]`
+`NSValue.CGVectorValue` (iOS)<br>`NSValue` containing `CGVector` (macOS) | `NSValue.cgVectorValue` (iOS)<br>`NSValue` containing `CGVector` (macOS)
+`NSValue.UIEdgeInsetsValue` (iOS)<br>`NSValue.edgeInsetsValue` (macOS) | `NSValue.uiEdgeInsetsValue` (iOS)<br>`NSValue.edgeInsetsValue` (macOS)
+
+For literal floating-point values, use `-[NSNumber numberWithDouble:]` instead
+of `-[NSNumber numberWithFloat:]` to avoid precision issues.
+
+### Key paths
+
+A key path expression refers to an attribute of the `MGLFeature` object being
+evaluated for display. For example, if a polygon’s `MGLFeature.attributes`
+dictionary contains the `floorCount` key, then the key path `floorCount` refers
+to the value of the `floorCount` attribute when evaluating that particular
+polygon.
+
+The following special attribute is also available on features that are produced
+as a result of clustering multiple point features together in a shape source:
+
+<table>
+<thead>
+<tr><th>Attribute</th><th>Type</th><th>Meaning</th></tr>
+</thead>
+<tbody>
+<tr>
+ <td><code>point_count</code></td>
+ <td>Number</td>
+ <td>The number of point features in a given cluster.</td>
+</tr>
+</tbody>
+</table>
+
+Some characters may not be used directly as part of a key path in a format
+string. For example, if a feature’s attribute is named `ISO 3166-1:2006`, an
+expression format string of `lowercase(ISO 3166-1:2006)` or a predicate format
+string of `ISO 3166-1:2006 == 'US-OH'` would raise an exception. Instead, use a
+`%K` placeholder or the `+[NSExpression expressionForKeyPath:]` initializer:
+
+```objc
+[NSPredicate predicateWithFormat:@"%K == 'US-OH'", @"ISO 3166-1:2006"];
+[NSExpression expressionForFunction:@"lowercase:"
+ arguments:@[[NSExpression expressionForKeyPath:@"ISO 3166-1:2006"]]]
+```
+
+```swift
+NSPredicate(format: "%K == 'US-OH'", "ISO 3166-1:2006")
+NSExpression(forFunction: "lowercase:",
+ arguments: [NSExpression(forKeyPath: "ISO 3166-1:2006")])
+```
+
+### Functions
+
+Of the
+[functions predefined](https://developer.apple.com/documentation/foundation/nsexpression/1413747-init#discussion)
+by the
+[`+[NSExpression expressionForFunction:arguments:]` method](https://developer.apple.com/documentation/foundation/nsexpression/1413747-init),
+the following subset is supported in layer attribute values:
+
+Initializer parameter | Format string syntax
+----------------------|---------------------
+`average:` | `average({1, 2, 2, 3, 4, 7, 9})`
+`sum:` | `sum({1, 2, 2, 3, 4, 7, 9})`
+`count:` | `count({1, 2, 2, 3, 4, 7, 9})`
+`min:` | `min({1, 2, 2, 3, 4, 7, 9})`
+`max:` | `max({1, 2, 2, 3, 4, 7, 9})`
+`add:to:` | `1 + 2`
+`from:subtract:` | `2 - 1`
+`multiply:by:` | `1 * 2`
+`divide:by:` | `1 / 2`
+`modulus:by:` | `modulus:by:(1, 2)`
+`sqrt:` | `sqrt(2)`
+`log:` | `log(10)`
+`ln:` | `ln(2)`
+`raise:toPower:` | `2 ** 2`
+`exp:` | `exp(0)`
+`ceiling:` | `ceiling(0.99999)`
+`abs:` | `abs(-1)`
+`trunc:` | `trunc(6378.1370)`
+`floor:` | `floor(-0.99999)`
+`uppercase:` | `uppercase('Elysian Fields')`
+`lowercase:` | `lowercase('DOWNTOWN')`
+`noindex:` | `noindex(0 + 2 + c)`
+`length:` | `length('Wapakoneta')`
+`castObject:toType:` | `CAST(ele, 'NSString')`<br>`CAST(ele, 'NSNumber')`
+
+A number of [Mapbox-specific functions](#mapbox-specific-functions) are also
+available.
+
+The following predefined functions are **not** supported:
+
+Initializer parameter | Format string syntax
+----------------------|---------------------
+`median:` | `median({1, 2, 2, 3, 4, 7, 9})`
+`mode:` | `mode({1, 2, 2, 3, 4, 7, 9})`
+`stddev:` | `stddev({1, 2, 2, 3, 4, 7, 9})`
+`random` | `random()`
+`randomn:` | `randomn(10)`
+`now` | `now()`
+`bitwiseAnd:with:` | `bitwiseAnd:with:(5, 3)`
+`bitwiseOr:with:` | `bitwiseOr:with:(5, 3)`
+`bitwiseXor:with:` | `bitwiseXor:with:(5, 3)`
+`leftshift:by:` | `leftshift:by:(23, 1)`
+`rightshift:by:` | `rightshift:by:(23, 1)`
+`onesComplement:` | `onesComplement(255)`
+`distanceToLocation:fromLocation:` | `distanceToLocation:fromLocation:(there, here)`
+
+### Conditionals
+
+Conditionals are supported via the built-in
+`+[NSExpression expressionForConditional:trueExpression:falseExpression:]`
+method and `TERNARY()` operator. If you need to express multiple cases
+(“else-if”), you can either nest a conditional within a conditional or use the
+[`MGL_IF()`](#code-mgl_if-code) or [`MGL_MATCH()`](#code-mgl_match-code) function.
+
+### Aggregates
+
+Aggregate expressions can contain arrays of expressions. In some cases, it is
+possible to use the array itself instead of wrapping the array in an aggregate
+expression.
+
+### Variables
+
+The following variables are defined by this SDK for use with style layers:
+
+<table>
+<thead>
+<tr><th>Variable</th><th>Type</th><th>Meaning</th></tr>
+</thead>
+<tbody>
+<tr>
+ <td><code>$featureIdentifier</code></td>
+ <td>
+ Any
+ <a href="working-with-geojson-data.html#about-geojson-deserialization">GeoJSON data type</a>
+ </td>
+ <td>
+ A value that uniquely identifies the feature in the containing source.
+ This variable corresponds to the
+ <code>NSExpression.featureIdentifierVariableExpression</code> property.
+ </td>
+</tr>
+<tr>
+ <td><code>$geometryType</code></td>
+ <td>String</td>
+ <td>
+ The type of geometry represented by the feature. A feature’s type is one
+ of the following strings:
+ <ul>
+ <li>
+ <code>Point</code> for point features, corresponding to the
+ <code>MGLPointAnnotation</code> class
+ </li>
+ <li>
+ <code>LineString</code> for polyline features, corresponding to
+ the <code>MGLPolyline</code> class
+ </li>
+ <li>
+ <code>Polygon</code> for polygon features, corresponding to the
+ <code>MGLPolygon</code> class
+ </li>
+ </ul>
+ This variable corresponds to the
+ <code>NSExpression.geometryTypeVariableExpression</code> property.
+ </td>
+</tr>
+<tr>
+ <td><code>$heatmapDensity</code></td>
+ <td>Number</td>
+ <td>
+ The
+ <a href="https://en.wikipedia.org/wiki/Kernel_density_estimation">kernel density estimation</a>
+ of a screen point in a heatmap layer; in other words, a relative measure
+ of how many data points are crowded around a particular pixel. This
+ variable can only be used with the <code>heatmapColor</code> property.
+ This variable corresponds to the
+ <code>NSExpression.heatmapDensityVariableExpression</code> property.
+ </td>
+</tr>
+<tr>
+ <td><code>$zoomLevel</code></td>
+ <td>Number</td>
+ <td>
+ The current zoom level. In style layout and paint properties, this
+ variable may only appear as the target of a top-level interpolation or
+ step expression. This variable corresponds to the
+ <code>NSExpression.zoomLevelVariableExpression</code> property.
+ </td>
+</tr>
+</tbody>
+</table>
+
+In addition to these variables, you can define your own variables and refer to
+them elsewhere in the expression. The syntax for defining a variable makes use
+of a [Mapbox-specific function](#mapbox-specific-functions) that takes an
+`NSDictionary` as an argument:
+
+```objc
+[NSExpression expressionWithFormat:@"MGL_LET('floorCount', 2, $floorCount + 1)"];
+```
+
+```swift
+NSExpression(format: "MGL_LET(floorCount, 2, $floorCount + 1)")
+```
+
+## Mapbox-specific functions
+
+For compatibility with the Mapbox Style Specification, the following functions
+are defined by this SDK. When setting a style layer property, you can call these
+functions just like the predefined functions above, using either the
+`+[NSExpression expressionForFunction:arguments:]` method or a convenient format
+string syntax:
+
+### `mgl_does:have:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_does:have:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>mgl_does:have:(SELF, '🧀🍔')</code> or <code>mgl_does:have:(%@, '🧀🍔')</code></dd>
+</dl>
+
+Returns a Boolean value indicating whether the dictionary has a value for the
+key or whether the evaluated object (`SELF`) has a value for the feature
+attribute. Compared to the [`mgl_has:`](#code-mgl_has-code) custom function,
+that function’s target is instead passed in as the first argument to this
+function. Both functions are equivalent to the syntax `key != NIL` or
+`%@[key] != NIL` but can be used outside of a predicate.
+
+### `mgl_interpolate:withCurveType:parameters:stops:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_interpolate:withCurveType:parameters:stops:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>mgl_interpolate:withCurveType:parameters:stops:(x, 'linear', nil, %@)</code></dd>
+</dl>
+
+Produces continuous, smooth results by interpolating between pairs of input and
+output values (“stops”). Compared to the
+[`mgl_interpolateWithCurveType:parameters:stops:`](#code-mgl_interpolatewithcurvetype-parameters-stops-code)
+custom function, the input expression (that function’s target) is instead passed
+in as the first argument to this function.
+
+### `mgl_step:from:stops:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_step:from:stops:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>mgl_step:from:stops:(x, 11, %@)</code></dd>
+</dl>
+
+Produces discrete, stepped results by evaluating a piecewise-constant function
+defined by pairs of input and output values ("stops"). Compared to the
+[`mgl_stepWithMinimum:stops:`](#code-mgl_stepwithminimum-stops-code) custom
+function, the input expression (that function’s target) is instead passed in as
+the first argument to this function.
+
+### `mgl_join:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_join:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>mgl_join({'Old', 'MacDonald'})</code></dd>
+</dl>
+
+Returns the result of concatenating together all the elements of an array in
+order. Compared to the
+[`stringByAppendingString:`](#code-stringbyappendingstring-code) custom
+function, this function takes only one argument, which is an aggregate
+expression containing the strings to concatenate.
+
+### `mgl_acos:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_acos:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>mgl_acos(1)</code></dd>
+</dl>
+
+Returns the arccosine of the number.
+
+This function corresponds to the
+[`acos`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-acos)
+operator in the Mapbox Style Specification.
+
+### `mgl_asin:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_asin:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>mgl_asin(0)</code></dd>
+</dl>
+
+Returns the arcsine of the number.
+
+This function corresponds to the
+[`asin`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-asin)
+operator in the Mapbox Style Specification.
+
+### `mgl_atan:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_atan:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>mgl_atan(20)</code></dd>
+</dl>
+
+Returns the arctangent of the number.
+
+This function corresponds to the
+[`atan`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-atan)
+operator in the Mapbox Style Specification.
+
+### `mgl_cos:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_cos:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>mgl_cos(0)</code></dd>
+</dl>
+
+Returns the cosine of the number.
+
+This function corresponds to the
+[`cos`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-cos)
+operator in the Mapbox Style Specification.
+
+### `mgl_log2:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_log2:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>mgl_log2(1024)</code></dd>
+</dl>
+
+Returns the base-2 logarithm of the number.
+
+This function corresponds to the
+[`log2`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-log2)
+operator in the Mapbox Style Specification.
+
+### `mgl_round:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_round:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>mgl_round(1.5)</code></dd>
+</dl>
+
+Returns the number rounded to the nearest integer. If the number is halfway
+between two integers, this function rounds it away from zero.
+
+This function corresponds to the
+[`round`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-round)
+operator in the Mapbox Style Specification.
+
+### `mgl_sin:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_sin:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>mgl_sin(0)</code></dd>
+</dl>
+
+Returns the sine of the number.
+
+This function corresponds to the
+[`sin`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-sin)
+operator in the Mapbox Style Specification.
+
+### `mgl_tan:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_tan:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>mgl_tan(0)</code></dd>
+</dl>
+
+Returns the tangent of the number.
+
+This function corresponds to the
+[`tan`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-tan)
+operator in the Mapbox Style Specification.
+
+### `mgl_coalesce:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_coalesce:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>mgl_coalesce({x, y, z})</code></dd>
+</dl>
+
+Returns the first non-`nil` value from an array of expressions.
+
+This function corresponds to the
+[`coalesce`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-coalesce)
+operator in the Mapbox Style Specification.
+
+### `MGL_LET`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>MGL_LET:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>MGL_LET('age', uppercase('old'), 'name', uppercase('MacDonald'), mgl_join({$age, $name}))</code></dd>
+<dt>Arguments:</dt>
+<dd>
+ Any number of variable names interspersed with their assigned
+ <code>NSExpression</code> values, followed by an <code>NSExpression</code>
+ that may contain references to those variables.
+</dd>
+</dl>
+
+Returns the result of evaluating an expression with the given variable values.
+Compared to the
+[`mgl_expressionWithContext:`](#code-mgl_expressionwithcontext-code) custom
+function, this function takes the variable names and values inline before the
+expression that contains references to those variables.
+
+### `MGL_MATCH`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>MGL_MATCH:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>MGL_MATCH(x, 0, 'zero match', 1, 'one match', 'two match', 'default')</code></dd>
+<dt>Arguments:</dt>
+<dd>
+ An input expression, then any number of argument pairs, followed by a default
+ expression. Each argument pair consists of a constant value followed by an
+ expression to produce as a result of matching that constant value.
+</dd>
+</dl>
+
+Returns the result of matching the input expression against the given constant
+values.
+
+This function corresponds to the
+`+[NSExpression(MGLAdditions) mgl_expressionForMatchingExpression:inDictionary:defaultExpression:]`
+method and the
+[`match`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-match)
+operator in the Mapbox Style Specification.
+
+### `MGL_IF`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>MGL_IF:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>MGL_IF(1 = 2, YES, 2 = 2, YES, NO)</code></dd>
+<dt>Arguments:</dt>
+<dd>
+ Alternating <code>NSPredicate</code> conditionals and resulting expressions,
+ followed by a default expression.
+</dd>
+</dl>
+
+Returns the first expression that meets the condition; otherwise, the default
+value. Unlike
+`+[NSExpression expressionForConditional:trueExpression:falseExpression:]` or
+the `TERNARY()` syntax, this function can accept multiple “if else” conditions
+and is supported on iOS 8._x_ and macOS 10.10._x_; however, each conditional
+passed into this function must be wrapped in a constant expression.
+
+This function corresponds to the
+`+[NSExpression(MGLAdditions) mgl_expressionForConditional:trueExpression:falseExpresssion:]`
+method and the
+[`case`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-case)
+operator in the Mapbox Style Specification.
+
+### `MGL_FUNCTION`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>MGL_FUNCTION:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>MGL_FUNCTION('typeof', mystery)</code></dd>
+<dt>Arguments:</dt>
+<dd>
+ Any arguments required by the expression operator.
+</dd>
+</dl>
+
+An expression exactly as defined by the
+[Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions).
+
+## Custom functions
+
+The following custom functions are also available with the
+`+[NSExpression expressionForFunction:selectorName:arguments:]` method or the
+`FUNCTION()` format string syntax.
+
+Some of these functions are defined as methods on their respective target
+classes, but you should not call them directly outside the context of an
+expression, because the result may differ from the evaluated expression’s result
+or may result in undefined behavior.
+
+The Mapbox Style Specification defines some operators for which no custom
+function is available. To use these operators in an `NSExpression`, call the
+[`MGL_FUNCTION()`](#code-mgl_function-code) function with the same arguments
+that the operator expects.
+
+### `boolValue`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>boolValue</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>FUNCTION(1, 'boolValue')</code></dd>
+<dt>Target:</dt>
+<dd>
+ An <code>NSExpression</code> that evaluates to a number or string.
+</dd>
+<dt>Arguments:</dt>
+<dd>None.</dd>
+</dl>
+
+A Boolean representation of the target: <code>FALSE</code> when then input is an
+empty string, 0, <code>FALSE</code>, <code>NIL</code>, or <code>NaN</code>,
+otherwise <code>TRUE</code>.
+
+### `mgl_has:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_has:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>FUNCTION($featureAttributes, 'mgl_has:', '🧀🍔')</code></dd>
+<dt>Target:</dt>
+<dd>
+ An <code>NSExpression</code> that evaluates to an <code>NSDictionary</code>
+ or the evaluated object (<code>SELF</code>).
+</dd>
+<dt>Arguments:</dt>
+<dd>
+ An <code>NSExpression</code> that evaluates to an <code>NSString</code>
+ representing the key to look up in the dictionary or the feature attribute to
+ look up in the evaluated object (see <code>MGLFeature.attributes</code>).
+</dd>
+</dl>
+
+<code>true</code> if the dictionary has a value for the key or if the evaluated
+object has a value for the feature attribute.
+
+This function corresponds to the
+[`has`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-has)
+operator in the Mapbox Style Specification. See also the
+[`mgl_does:have:`](#code-mgl_does-have-code) function, which is used on its own
+without the `FUNCTION()` operator. You can also check whether an object has an
+attribute by comparing the key path to `NIL`, for example `cheeseburger != NIL`
+or `burger.cheese != NIL`
+
+### `mgl_expressionWithContext:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_expressionWithContext:</code></dd>
+<dt>Format string syntax:</dt>
+<dd>
+ <code>FUNCTION($ios + $macos, 'mgl_expressionWithContext:', %@)</code> with
+ a dictionary containing <code>ios</code> and <code>macos</code> keys
+</dd>
+<dt>Target:</dt>
+<dd>
+ An <code>NSExpression</code> that may contain references to the variables
+ defined in the context dictionary.
+</dd>
+<dt>Arguments:</dt>
+<dd>
+ An <code>NSDictionary</code> with <code>NSString</code>s as keys and
+ <code>NSExpression</code>s as values. Each key is a variable name and each
+ value is the variable’s value within the target expression.
+</dd>
+</dl>
+
+The target expression with variable subexpressions replaced with the values
+defined in the context dictionary.
+
+This function corresponds to the
+[`let`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-let)
+operator in the Mapbox Style Specification. See also the
+[`MGL_LET`](#code-mgl_let-code) function, which is used on its own without the
+`FUNCTION()` operator.
+
+### `mgl_interpolateWithCurveType:parameters:stops:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_interpolateWithCurveType:parameters:stops:</code></dd>
+<dt>Format string syntax:</dt>
+<dd>
+ <code>FUNCTION($zoomLevel, 'mgl_interpolateWithCurveType:parameters:stops:', 'linear', NIL, %@)</code>
+ with a dictionary containing zoom levels or other constant values as keys
+</dd>
+<dt>Target:</dt>
+<dd>
+ An <code>NSExpression</code> that evaluates to a number and contains a
+ variable or key path expression.
+</dd>
+<dt>Arguments:</dt>
+<dd>
+ The first argument is one of the following strings denoting curve types:
+ <code>linear</code>, <code>exponential</code>, or <code>cubic-bezier</code>.
+
+ The second argument is an expression providing parameters for the curve:
+
+ <ul>
+ <li>If the curve type is <code>linear</code>, the argument is <code>NIL</code>.</li>
+ <li>
+ If the curve type is <code>exponential</code>, the argument is an
+ expression that evaluates to a number, specifying the base of the
+ exponential interpolation.
+ </li>
+ <li>
+ If the curve type is <code>cubic-bezier</code>, the argument is an
+ array or aggregate expression containing four expressions, each
+ evaluating to a number. The four numbers are control points for the
+ cubic Bézier curve.
+ </li>
+ </ul>
+
+ The third argument is an <code>NSDictionary</code> object representing the
+ interpolation’s stops, with numeric zoom levels as keys and expressions as
+ values.
+</dd>
+</dl>
+
+A value interpolated along the continuous mathematical function defined by the
+arguments, with the target as the input to the function.
+
+The input expression is matched against the keys in the stop dictionary. The
+keys may be feature attribute values, zoom levels, or heatmap densities. The
+values may be constant values or `NSExpression` objects. For example, you can
+use a stop dictionary with the zoom levels 0, 10, and 20 as keys and the colors
+yellow, orange, and red as the values.
+
+This function corresponds to the
+`+[NSExpression(MGLAdditions) mgl_expressionForInterpolatingExpression:withCurveType:parameters:stops:]`
+method and the
+[`interpolate`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-interpolate)
+operator in the Mapbox Style Specification. See also the
+[`mgl_interpolate:withCurveType:parameters:stops:`](#code-mgl_interpolate-withcurvetype-parameters-stops-code)
+function, which is used on its own without the `FUNCTION()` operator.
+
+### `mgl_numberWithFallbackValues:`
+
+<dl>
+<dt>Selector:</dt>
+<dd>
+ <code>mgl_numberWithFallbackValues:</code>,
+ <code>doubleValue</code>,
+ <code>floatValue</code>, or
+ <code>decimalValue</code>
+</dd>
+<dt>Format string syntax:</dt>
+<dd><code>FUNCTION(ele, 'mgl_numberWithFallbackValues:', 0)</code></dd>
+<dt>Target:</dt>
+<dd>
+ An <code>NSExpression</code> that evaluates to a Boolean value, number, or
+ string.
+</dd>
+<dt>Arguments:</dt>
+<dd>
+ Zero or more <code>NSExpression</code>s, each evaluating to a Boolean value
+ or string.
+</dd>
+</dl>
+
+A numeric representation of the target:
+
+* If the target is <code>NIL</code> or <code>FALSE</code>, the result is 0.
+* If the target is true, the result is 1.
+ * If the target is a string, it is converted to a number as specified by the
+ “[ToNumber Applied to the String Type](https://tc39.github.io/ecma262/#sec-tonumber-applied-to-the-string-type)”
+ algorithm of the ECMAScript Language Specification.
+ * If multiple values are provided, each one is evaluated in order until the
+ first successful conversion is obtained.
+
+This function corresponds to the
+[`to-number`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-to-number)
+operator in the Mapbox Style Specification. You can also cast a value to a
+number by passing the value and the string `NSNumber` into the `CAST()`
+operator.
+
+### `mgl_stepWithMinimum:stops:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>mgl_stepWithMinimum:stops:</code></dd>
+<dt>Format string syntax:</dt>
+<dd>
+ <code>FUNCTION($zoomLevel, 'mgl_stepWithMinimum:stops:', 0, %@)</code> with
+ a dictionary with zoom levels or other constant values as keys
+</dd>
+<dt>Target:</dt>
+<dd>
+ An <code>NSExpression</code> that evaluates to a number and contains a
+ variable or key path expression.
+</dd>
+<dt>Arguments:</dt>
+<dd>
+ The first argument is an expression that evaluates to a number, specifying
+ the minimum value in case the target is less than any of the stops in the
+ second argument.
+
+ The second argument is an <code>NSDictionary</code> object representing the
+ interpolation’s stops, with numeric zoom levels as keys and expressions as
+ values.
+</dd>
+</dl>
+
+The output value of the stop whose key is just less than the evaluated target,
+or the minimum value if the target is less than the least of the stops’ keys.
+
+The input expression is matched against the keys in the stop dictionary. The
+keys may be feature attribute values, zoom levels, or heatmap densities. The
+values may be constant values or `NSExpression` objects. For example, you can
+use a stop dictionary with the zoom levels 0, 10, and 20 as keys and the colors
+yellow, orange, and red as the values.
+
+This function corresponds to the
+`+[NSExpression(MGLAdditions) mgl_expressionForSteppingExpression:fromExpression:stops:]`
+method and the
+[`step`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-step)
+operator in the Mapbox Style Specification.
+
+### `stringByAppendingString:`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>stringByAppendingString:</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>FUNCTION('Old', 'stringByAppendingString:', 'MacDonald')</code></dd>
+<dt>Target:</dt>
+<dd>An <code>NSExpression</code> that evaluates to a string.</dd>
+<dt>Arguments:</dt>
+<dd>One or more <code>NSExpression</code>s, each evaluating to a string.</dd>
+</dl>
+
+The target string with each of the argument strings appended in order.
+
+This function corresponds to the
+`-[NSExpression(MGLAdditions) mgl_expressionByAppendingExpression:]`
+method and is similar to the
+[`concat`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-concat)
+operator in the Mapbox Style Specification. See also the
+[`mgl_join:`](#code-mgl_join-code) function, which concatenates multiple
+expressions and is used on its own without the `FUNCTION()` operator.
+
+### `stringValue`
+
+<dl>
+<dt>Selector:</dt>
+<dd><code>stringValue</code></dd>
+<dt>Format string syntax:</dt>
+<dd><code>FUNCTION(ele, 'stringValue')</code></dd>
+<dt>Target:</dt>
+<dd>
+ An <code>NSExpression</code> that evaluates to a Boolean value, number, or
+ string.
+</dd>
+<dt>Arguments:</dt>
+<dd>None.</dd>
+</dl>
+
+A string representation of the target:
+
+* If the target is <code>NIL</code>, the result is the empty string.
+* If the target is a Boolean value, the result is the string `true` or `false`.
+* If the target is a number, it is converted to a string as specified by the
+ “[NumberToString](https://tc39.github.io/ecma262/#sec-tostring-applied-to-the-number-type)”
+ algorithm of the ECMAScript Language Specification.
+* If the target is a color, it is converted to a string of the form
+ `rgba(r,g,b,a)`, where <var>r</var>, <var>g</var>, and <var>b</var> are
+ numerals ranging from 0 to 255 and <var>a</var> ranges from 0 to 1.
+* Otherwise, the target is converted to a string in the format specified by the
+ [`JSON.stringify()`](https://tc39.github.io/ecma262/#sec-json.stringify)
+ function of the ECMAScript Language Specification.
+
+This function corresponds to the
+[`to-string`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-to-string)
+operator in the Mapbox Style Specification. You can also cast a value to a
+string by passing the value and the string `NSString` into the `CAST()`
+operator.
diff --git a/platform/darwin/docs/guides/Tile URL Templates.md.ejs b/platform/darwin/docs/guides/Tile URL Templates.md.ejs
index 78fb297138..2b1de65b42 100644
--- a/platform/darwin/docs/guides/Tile URL Templates.md.ejs
+++ b/platform/darwin/docs/guides/Tile URL Templates.md.ejs
@@ -10,12 +10,12 @@
-->
# Tile URL Templates
-`MGLTileSource` objects, specifically `MGLRasterSource` and `MGLVectorSource`
-objects, can be created using an initializer that accepts an array of tile URL
-templates. Tile URL templates are strings that specify the URLs of the vector
-tiles or raster tile images to load. A template resembles an absolute URL, but
-with any number of placeholder strings that the source evaluates based on the
-tile it needs to load. For example:
+`MGLTileSource` objects, specifically `MGLRasterTileSource` and
+`MGLVectorTileSource` objects, can be created using an initializer that accepts
+an array of tile URL templates. Tile URL templates are strings that specify the
+URLs of the vector tiles or raster tile images to load. A template resembles an
+absolute URL, but with any number of placeholder strings that the source
+evaluates based on the tile it needs to load. For example:
* `http://www.example.com/tiles/{z}/{x}/{y}.pbf` could be
evaluated as `http://www.example.com/tiles/14/6/9.pbf`.
@@ -62,7 +62,7 @@ all of which are optional:
<td>The tile’s zoom level. At zoom level 0, each tile covers the entire
world map; at zoom level 1, it covers ¼ of the world; at zoom level 2,
<sup>1</sup>⁄<sub>16</sub> of the world, and so on. For tiles loaded by
- a <code>MGLRasterSource</code> object, whether the tile zoom level
+ a <code>MGLRasterTileSource</code> object, whether the tile zoom level
matches the map’s current zoom level depends on the value of the
source’s tile size as specified in the
<code>MGLTileSourceOptionTileSize</code> key of the <code>options</code>
diff --git a/platform/darwin/docs/guides/Using Style Functions at Runtime.md.ejs b/platform/darwin/docs/guides/Using Style Functions at Runtime.md.ejs
deleted file mode 100644
index e41ac1c832..0000000000
--- a/platform/darwin/docs/guides/Using Style Functions at Runtime.md.ejs
+++ /dev/null
@@ -1,99 +0,0 @@
-<%
- const os = locals.os;
- const iOS = os === 'iOS';
- const macOS = os === 'macOS';
- const cocoaPrefix = iOS ? 'UI' : 'NS';
- const guide = 'UsingStyleFunctionsAtRuntime';
--%>
-<!--
- This file is generated.
- Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
--->
-
-# Using Style Functions at Runtime
-
-[Runtime Styling](runtime-styling.html) enables you to modify every aspect of the map’s appearance dynamically as a user interacts with your application. Much of the runtime styling API allows you to specify _style functions_ instead of constant values. A style function allows you to specify in advance how a layout or paint attribute will vary as the zoom level changes or how the appearance of individual features vary based on metadata provided by a content source.
-
-Style functions spare you the inconvenience of manually calculating intermediate values between different zoom levels or creating a multitude of style layers to handle homogeneous features in the map content. For example, if your content source indicates the prices of hotels in an area, you can color-code the hotels by price, relying on a style function to smoothly interpolate among desired colors without having to specify the color for each exact price.
-
-_Data-driven styling_ specifically refers to the use of style functions to vary the map’s appearance based on data in a content source.
-
-You can also specify style functions in a style JSON file, to be applied automatically when the map loads. See the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-js/style-spec/#types-function) for details.
-
-![available bikes](img/data-driven-styling/citibikes.png) ![subway lines](img/data-driven-styling/polylineExample.png)
-
-This guide uses earthquake data from the [U.S. Geological Survey](https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php) and data-driven styling to style a map based on attributes. For more information about how to work with GeoJSON data in our iOS SDK, please see our [working with GeoJSON data](working-with-geojson-data.html) guide.
-
-A style function is represented at runtime by the `MGLStyleFunction` class. There are three subclasses of `MGLStyleFunction`:
-
-* `MGLCameraStyleFunction` is a style value that changes with zoom level. For example, you can make the radius of a circle increase according to zoom level.
-* `MGLSourceStyleFunction` is a style value that changes with the attributes of a feature. For example, you can adjust the radius of a circle based on the magnitude of an earthquake.
-* `MGLCompositeStyleFunction` is a style value that changes with both zoom level and attribute values. For example, you can add a circle layer where each circle has a radius based on both zoom level and the magnitude of an earthquake.
-
-The documentation for each individual style layer property notes which style functions are enabled for that property.
-
-## Stops
-
-Stops are key-value pairs that that determine a style value. With a `MGLCameraSourceFunction` stop, you can use a dictionary with a zoom level for a key and a `MGLStyleValue` for the value. For example, you can use a stops dictionary with zoom levels 0, 10, and 20 as keys, and yellow, orange, and red as the values. A `MGLSourceStyleFunction` uses the relevant attribute value as the key.
-
-<%- guideExample(guide, 'Stops', os) %>
-
-## Interpolation mode
-
-The effect a key has on the style value is determined by the interpolation mode. There are four interpolation modes that can be used with a source style function: exponential, interval, categorical, and identity. You can also use exponential and interval interpolation modes with a camera style function.
-
-### Linear
-
-`MGLInterpolationModeExponential` interpolates linearly or exponentially between style function stop values. By default, the `MGLStyleFunction` options parameter `MGLStyleFunctionOptionInterpolationBase` equals `1`, which represents linear interpolation and doesn’t need to be included in the options dictionary.
-
-The stops dictionary below, for example, shows colors that continuously shift from yellow to orange to red to blue to white based on the attribute value.
-
-<%- guideExample(guide, 'Linear', os) %>
-
-![exponential mode](img/data-driven-styling/exponential.png)
-
-### Exponential
-
-By combining `MGLInterpolationModeExponential` with an `MGLStyleFunctionOptionInterpolationBase` greater than `0` (other than `1`), you can interpolate between values exponentially, create an accelerated ramp effect.
-
-Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](working-with-mapbox-studio.html)) comparing interpolation base values of `1.5` and `0.5` based on zoom.
-
-<img src="img/data-driven-styling/exponential-function.png" height=344/>
-<img src="img/data-driven-styling/exponential-function-1.png" height=344/>
-
-The example below increases a layer’s `circleRadius` exponentially based on a map’s zoom level. The `MGLStyleFunctionOptionInterpolationBase` is `1.5`.
-
-<%- guideExample(guide, 'Exponential', os) %>
-
-### Interval
-
-`MGLInterpolationModeInterval` creates a range using the keys from the stops dictionary. The range is from the given key to just less than the next key. The attribute values that fall into that range are then styled using the style value assigned to that key.
-
-When we use the stops dictionary given above with an interval interpolation mode, we create ranges where earthquakes with a magnitude of 0 to just less than 2.5 would be yellow, 2.5 to just less than 5 would be orange, and so on.
-
-<%- guideExample(guide, 'Interval', os) %>
-
-![interval mode](img/data-driven-styling/interval.png)
-
-### Categorical
-
-At each stop, `MGLInterpolationModeCategorical` produces an output value equal to the function input. We’re going to use a different stops dictionary than we did for the previous two modes.
-
-There are three main types of events in the dataset: earthquakes, explosions, and quarry blasts. In this case, the color of the circle layer will be determined by the type of event, with a default value of blue to catch any events that do not fall into any of those categories.
-
-<%- guideExample(guide, 'Categorical', os) %>
-
-![categorical mode](img/data-driven-styling/categorical1.png) ![categorical mode](img/data-driven-styling/categorical2.png)
-
-### Identity
-
-`MGLInterpolationModeIdentity` uses the attribute’s value as the style value. For example, you can set the `circleRadius` to the earthquake’s magnitude. Since the attribute value itself will be used as the style value, `sourceStops` should be set to `nil`.
-
-<%- guideExample(guide, 'Identity', os) %>
-
-![identity mode](img/data-driven-styling/identity.png)
-
-##Resources
-
-* [USGS](https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php)
-* [For Style Authors](for-style-authors.html)
diff --git a/platform/darwin/docs/img/data-driven-styling/cast.png b/platform/darwin/docs/img/data-driven-styling/cast.png
new file mode 100644
index 0000000000..e5b40b4ffa
--- /dev/null
+++ b/platform/darwin/docs/img/data-driven-styling/cast.png
Binary files differ
diff --git a/platform/darwin/docs/img/data-driven-styling/categorical1.png b/platform/darwin/docs/img/data-driven-styling/categorical1.png
deleted file mode 100644
index 969846b41b..0000000000
--- a/platform/darwin/docs/img/data-driven-styling/categorical1.png
+++ /dev/null
Binary files differ
diff --git a/platform/darwin/docs/img/data-driven-styling/categorical2.png b/platform/darwin/docs/img/data-driven-styling/categorical2.png
deleted file mode 100644
index 5008c522ed..0000000000
--- a/platform/darwin/docs/img/data-driven-styling/categorical2.png
+++ /dev/null
Binary files differ
diff --git a/platform/darwin/docs/img/data-driven-styling/citibikes.png b/platform/darwin/docs/img/data-driven-styling/citibikes.png
deleted file mode 100644
index a616672a32..0000000000
--- a/platform/darwin/docs/img/data-driven-styling/citibikes.png
+++ /dev/null
Binary files differ
diff --git a/platform/darwin/docs/img/data-driven-styling/exponential-function-1.png b/platform/darwin/docs/img/data-driven-styling/exponential-function-1.png
index 6aa129a305..39a8a2a1e4 100644
--- a/platform/darwin/docs/img/data-driven-styling/exponential-function-1.png
+++ b/platform/darwin/docs/img/data-driven-styling/exponential-function-1.png
Binary files differ
diff --git a/platform/darwin/docs/img/data-driven-styling/exponential-function.png b/platform/darwin/docs/img/data-driven-styling/exponential-function.png
index c14969f0a8..f9824fc5e4 100644
--- a/platform/darwin/docs/img/data-driven-styling/exponential-function.png
+++ b/platform/darwin/docs/img/data-driven-styling/exponential-function.png
Binary files differ
diff --git a/platform/darwin/docs/img/data-driven-styling/exponential.png b/platform/darwin/docs/img/data-driven-styling/exponential.png
deleted file mode 100644
index 87ddc1350e..0000000000
--- a/platform/darwin/docs/img/data-driven-styling/exponential.png
+++ /dev/null
Binary files differ
diff --git a/platform/darwin/docs/img/data-driven-styling/identity.png b/platform/darwin/docs/img/data-driven-styling/identity.png
index 632ccdf3d5..3355694ec9 100644
--- a/platform/darwin/docs/img/data-driven-styling/identity.png
+++ b/platform/darwin/docs/img/data-driven-styling/identity.png
Binary files differ
diff --git a/platform/darwin/docs/img/data-driven-styling/interval.png b/platform/darwin/docs/img/data-driven-styling/interval.png
deleted file mode 100644
index d15aff2025..0000000000
--- a/platform/darwin/docs/img/data-driven-styling/interval.png
+++ /dev/null
Binary files differ
diff --git a/platform/darwin/docs/img/data-driven-styling/multiply.png b/platform/darwin/docs/img/data-driven-styling/multiply.png
new file mode 100644
index 0000000000..df42f243e1
--- /dev/null
+++ b/platform/darwin/docs/img/data-driven-styling/multiply.png
Binary files differ
diff --git a/platform/darwin/docs/img/data-driven-styling/polylineExample.png b/platform/darwin/docs/img/data-driven-styling/polylineExample.png
deleted file mode 100644
index cd9b39bae4..0000000000
--- a/platform/darwin/docs/img/data-driven-styling/polylineExample.png
+++ /dev/null
Binary files differ
diff --git a/platform/darwin/docs/theme/assets/css/jazzy.css.scss b/platform/darwin/docs/theme/assets/css/jazzy.css.scss
index ad0a3b7082..ff6d2a374c 100644
--- a/platform/darwin/docs/theme/assets/css/jazzy.css.scss
+++ b/platform/darwin/docs/theme/assets/css/jazzy.css.scss
@@ -113,7 +113,12 @@ h2 {
}
h3 {
- @include heading(14px, 1em 0 0.3em);
+ @include heading(1.2rem, 1em 0 0.3em);
+}
+
+h3 > code {
+ font-weight: bold;
+ font-size: 1.2rem;
}
h4 {
diff --git a/platform/darwin/mbgl/gl/gl_impl.hpp b/platform/darwin/mbgl/gl/gl_impl.hpp
new file mode 100644
index 0000000000..b4c062a474
--- /dev/null
+++ b/platform/darwin/mbgl/gl/gl_impl.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "TargetConditionals.h"
+#if TARGET_OS_IPHONE
+ #include <OpenGLES/ES2/gl.h>
+ #include <OpenGLES/ES2/glext.h>
+#elif TARGET_IPHONE_SIMULATOR
+ #include <OpenGLES/ES2/gl.h>
+ #include <OpenGLES/ES2/glext.h>
+#elif TARGET_OS_MAC
+ #include <OpenGL/OpenGL.h>
+ #include <OpenGL/gl.h>
+ #include <OpenGL/glext.h>
+#else
+ #error Unsupported Apple platform
+#endif
diff --git a/platform/darwin/mbgl/util/image+MGLAdditions.hpp b/platform/darwin/mbgl/util/image+MGLAdditions.hpp
index c738b4523d..c5343af4de 100644
--- a/platform/darwin/mbgl/util/image+MGLAdditions.hpp
+++ b/platform/darwin/mbgl/util/image+MGLAdditions.hpp
@@ -5,7 +5,7 @@
#include <CoreGraphics/CGImage.h>
// Creates a CGImage from a PremultipliedImage, taking over the memory ownership.
-CGImageRef CGImageFromMGLPremultipliedImage(mbgl::PremultipliedImage&&);
+CGImageRef CGImageCreateWithMGLPremultipliedImage(mbgl::PremultipliedImage&&);
// Creates a PremultipliedImage by copying the pixels of the CGImage.
// Does not alter the retain count of the supplied CGImage.
diff --git a/platform/darwin/resources/ca.lproj/Foundation.strings b/platform/darwin/resources/ca.lproj/Foundation.strings
index e60546d3c2..06bd2e8261 100644
--- a/platform/darwin/resources/ca.lproj/Foundation.strings
+++ b/platform/darwin/resources/ca.lproj/Foundation.strings
Binary files differ
diff --git a/platform/darwin/resources/da.lproj/Foundation.strings b/platform/darwin/resources/da.lproj/Foundation.strings
new file mode 100644
index 0000000000..d8d18f453c
--- /dev/null
+++ b/platform/darwin/resources/da.lproj/Foundation.strings
@@ -0,0 +1,297 @@
+/* Clock position format, long: {hours} o’clock */
+"CLOCK_FMT_LONG" = "%@ klokken";
+
+/* Clock position format, medium: {hours} o’clock */
+"CLOCK_FMT_MEDIUM" = "%@ klokken";
+
+/* Clock position format, short: {hours}:00 */
+"CLOCK_FMT_SHORT" = "%@:00";
+
+/* East, long */
+"COMPASS_E_LONG" = "øst";
+
+/* East, short */
+"COMPASS_E_SHORT" = "Ø";
+
+/* East by north, long */
+"COMPASS_EbN_LONG" = "øst via nord";
+
+/* East by north, short */
+"COMPASS_EbN_SHORT" = "ØvN";
+
+/* East by south, long */
+"COMPASS_EbS_LONG" = "øst via syd";
+
+/* East by south, short */
+"COMPASS_EbS_SHORT" = "ØvS";
+
+/* East-northeast, long */
+"COMPASS_ENE_LONG" = "øst-nordøst";
+
+/* East-northeast, short */
+"COMPASS_ENE_SHORT" = "ØNØ";
+
+/* East-southeast, long */
+"COMPASS_ESE_LONG" = "øst-sydøst";
+
+/* East-southeast, short */
+"COMPASS_ESE_SHORT" = "ØSØ";
+
+/* North, long */
+"COMPASS_N_LONG" = "nord";
+
+/* North, short */
+"COMPASS_N_SHORT" = "N";
+
+/* North by east, long */
+"COMPASS_NbE_LONG" = "nord via øst";
+
+/* North by east, short */
+"COMPASS_NbE_SHORT" = "NvØ";
+
+/* North by west, long */
+"COMPASS_NbW_LONG" = "nord via vest";
+
+/* North by west, short */
+"COMPASS_NbW_SHORT" = "NvV";
+
+/* Northeast, long */
+"COMPASS_NE_LONG" = "nordøst";
+
+/* Northeast, short */
+"COMPASS_NE_SHORT" = "NØ";
+
+/* Northeast by east, long */
+"COMPASS_NEbE_LONG" = "nordøst via øst";
+
+/* Northeast by east, short */
+"COMPASS_NEbE_SHORT" = "NØvØ";
+
+/* Northeast by north, long */
+"COMPASS_NEbN_LONG" = "nordøst via nord";
+
+/* Northeast by north, short */
+"COMPASS_NEbN_SHORT" = "NØvN";
+
+/* North-northeast, long */
+"COMPASS_NNE_LONG" = "nord-nordøst";
+
+/* North-northeast, short */
+"COMPASS_NNE_SHORT" = "NNØ";
+
+/* North-northwest, long */
+"COMPASS_NNW_LONG" = "nord-nordvest";
+
+/* North-northwest, short */
+"COMPASS_NNW_SHORT" = "NNV";
+
+/* Northwest, long */
+"COMPASS_NW_LONG" = "nordvest";
+
+/* Northwest, short */
+"COMPASS_NW_SHORT" = "NV";
+
+/* Northwest by north, long */
+"COMPASS_NWbN_LONG" = "nordvest via nord";
+
+/* Northwest by north, short */
+"COMPASS_NWbN_SHORT" = "NVvN";
+
+/* Northwest by west, long */
+"COMPASS_NWbW_LONG" = "nordvest via vest";
+
+/* Northwest by west, short */
+"COMPASS_NWbW_SHORT" = "NVvW";
+
+/* South, long */
+"COMPASS_S_LONG" = "syd";
+
+/* South, short */
+"COMPASS_S_SHORT" = "S";
+
+/* South by east, long */
+"COMPASS_SbE_LONG" = "syd via øst";
+
+/* South by east, short */
+"COMPASS_SbE_SHORT" = "SvØ";
+
+/* South by west, long */
+"COMPASS_SbW_LONG" = "syd via vest";
+
+/* South by west, short */
+"COMPASS_SbW_SHORT" = "SvV";
+
+/* Southeast, long */
+"COMPASS_SE_LONG" = "sydøst";
+
+/* Southeast, short */
+"COMPASS_SE_SHORT" = "SØ";
+
+/* Southeast by east, long */
+"COMPASS_SEbE_LONG" = "sydøst via øst";
+
+/* Southeast by east, short */
+"COMPASS_SEbE_SHORT" = "SØvØ";
+
+/* Southeast by south, long */
+"COMPASS_SEbS_LONG" = "sydøst via syd";
+
+/* Southeast by south, short */
+"COMPASS_SEbS_SHORT" = "SØvS";
+
+/* South-southeast, long */
+"COMPASS_SSE_LONG" = "syd-sydøst";
+
+/* South-southeast, short */
+"COMPASS_SSE_SHORT" = "SSØ";
+
+/* South-southwest, long */
+"COMPASS_SSW_LONG" = "syd-sydvest";
+
+/* South-southwest, short */
+"COMPASS_SSW_SHORT" = "SSV";
+
+/* Southwest, long */
+"COMPASS_SW_LONG" = "sydvest";
+
+/* Southwest, short */
+"COMPASS_SW_SHORT" = "SV";
+
+/* Southwest by south, long */
+"COMPASS_SWbS_LONG" = "sydvest via syd";
+
+/* Southwest by south, short */
+"COMPASS_SWbS_SHORT" = "SVvS";
+
+/* Southwest by west, long */
+"COMPASS_SWbW_LONG" = "sydvest via vest";
+
+/* Southwest by west, short */
+"COMPASS_SWbW_SHORT" = "SVvV";
+
+/* West, long */
+"COMPASS_W_LONG" = "vest";
+
+/* West, short */
+"COMPASS_W_SHORT" = "V";
+
+/* West by north, long */
+"COMPASS_WbN_LONG" = "vest via nord";
+
+/* West by north, short */
+"COMPASS_WbN_SHORT" = "VvN";
+
+/* West by south, long */
+"COMPASS_WbS_LONG" = "vest via syd";
+
+/* West by south, short */
+"COMPASS_WbS_SHORT" = "VvS";
+
+/* West-northwest, long */
+"COMPASS_WNW_LONG" = "vest-nordvest";
+
+/* West-northwest, short */
+"COMPASS_WNW_SHORT" = "VNV";
+
+/* West-southwest, long */
+"COMPASS_WSW_LONG" = "vest-sydvest";
+
+/* West-southwest, short */
+"COMPASS_WSW_SHORT" = "VSV";
+
+/* Degrees format, long */
+"COORD_DEG_LONG" = "%d grad(er)";
+
+/* Degrees format, medium: {degrees} */
+"COORD_DEG_MEDIUM" = "%d°";
+
+/* Degrees format, short: {degrees} */
+"COORD_DEG_SHORT" = "%d°";
+
+/* Coordinate format, long: {degrees}{minutes} */
+"COORD_DM_LONG" = "%1$@ og %2$@";
+
+/* Coordinate format, medium: {degrees}{minutes} */
+"COORD_DM_MEDIUM" = "%1$@%2$@";
+
+/* Coordinate format, short: {degrees}{minutes} */
+"COORD_DM_SHORT" = "%1$@%2$@";
+
+/* Coordinate format, long: {degrees}{minutes}{seconds} */
+"COORD_DMS_LONG" = "%1$@, %2$@, og %3$@";
+
+/* Coordinate format, medium: {degrees}{minutes}{seconds} */
+"COORD_DMS_MEDIUM" = "%1$@%2$@%3$@";
+
+/* Coordinate format, short: {degrees}{minutes}{seconds} */
+"COORD_DMS_SHORT" = "%1$@%2$@%3$@";
+
+/* East longitude format, long: {longitude} */
+"COORD_E_LONG" = "%@ øst";
+
+/* East longitude format, medium: {longitude} */
+"COORD_E_MEDIUM" = "%@ øst";
+
+/* East longitude format, short: {longitude} */
+"COORD_E_SHORT" = "%@Ø";
+
+/* Coordinate pair format, long: {latitude}, {longitude} */
+"COORD_FMT_LONG" = "%1$@ via %2$@";
+
+/* Coordinate pair format, medium: {latitude}, {longitude} */
+"COORD_FMT_MEDIUM" = "%1$@, %2$@";
+
+/* Coordinate pair format, short: {latitude}, {longitude} */
+"COORD_FMT_SHORT" = "%1$@, %2$@";
+
+/* Minutes format, long */
+"COORD_MIN_LONG" = "%d minut(ter)";
+
+/* Minutes format, medium: {minutes} */
+"COORD_MIN_MEDIUM" = "%d′";
+
+/* Minutes format, short: {minutes} */
+"COORD_MIN_SHORT" = "%d′";
+
+/* North latitude format, long: {latitude} */
+"COORD_N_LONG" = "%@ nord";
+
+/* North latitude format, medium: {latitude} */
+"COORD_N_MEDIUM" = "%@ nord";
+
+/* North latitude format, short: {latitude} */
+"COORD_N_SHORT" = "%@N";
+
+/* South latitude format, long: {latitude} */
+"COORD_S_LONG" = "%@ syd";
+
+/* South latitude format, medium: {latitude} */
+"COORD_S_MEDIUM" = "%@ syd";
+
+/* South latitude format, short: {latitude} */
+"COORD_S_SHORT" = "%@S";
+
+/* Seconds format, long */
+"COORD_SEC_LONG" = "%d sekunde(r)";
+
+/* Seconds format, medium: {seconds} */
+"COORD_SEC_MEDIUM" = "%d″";
+
+/* Seconds format, short: {seconds} */
+"COORD_SEC_SHORT" = "%d″";
+
+/* West longitude format, long: {longitude} */
+"COORD_W_LONG" = "%@ vest";
+
+/* West longitude format, medium: {longitude} */
+"COORD_W_MEDIUM" = "%@ vest";
+
+/* West longitude format, short: {longitude} */
+"COORD_W_SHORT" = "%@V";
+
+/* OpenStreetMap full name attribution */
+"OSM_FULL_NAME" = "OpenStreetMap";
+
+/* OpenStreetMap short name attribution */
+"OSM_SHORT_NAME" = "OSM";
+
diff --git a/platform/darwin/resources/da.lproj/Foundation.stringsdict b/platform/darwin/resources/da.lproj/Foundation.stringsdict
new file mode 100644
index 0000000000..17983b8aa8
--- /dev/null
+++ b/platform/darwin/resources/da.lproj/Foundation.stringsdict
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>COORD_DEG_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@degrees@</string>
+ <key>degrees</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d grad</string>
+ <key>other</key>
+ <string>%d grader</string>
+ </dict>
+ </dict>
+ <key>COORD_MIN_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@minutes@</string>
+ <key>minutes</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d minut</string>
+ <key>other</key>
+ <string>%d minutter</string>
+ </dict>
+ </dict>
+ <key>COORD_SEC_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@seconds@</string>
+ <key>seconds</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d sekund</string>
+ <key>other</key>
+ <string>%d sekunder</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/darwin/resources/de.lproj/Foundation.strings b/platform/darwin/resources/de.lproj/Foundation.strings
index fb4b1e874a..9c7242bb72 100644
--- a/platform/darwin/resources/de.lproj/Foundation.strings
+++ b/platform/darwin/resources/de.lproj/Foundation.strings
Binary files differ
diff --git a/platform/darwin/resources/fr.lproj/Foundation.strings b/platform/darwin/resources/fr.lproj/Foundation.strings
index ed38a264cf..6ad3fc554b 100644
--- a/platform/darwin/resources/fr.lproj/Foundation.strings
+++ b/platform/darwin/resources/fr.lproj/Foundation.strings
Binary files differ
diff --git a/platform/darwin/resources/he.lproj/Foundation.strings b/platform/darwin/resources/he.lproj/Foundation.strings
new file mode 100644
index 0000000000..2f6e24d6e6
--- /dev/null
+++ b/platform/darwin/resources/he.lproj/Foundation.strings
@@ -0,0 +1,297 @@
+/* Clock position format, long: {hours} o’clock */
+"CLOCK_FMT_LONG" = "שעה %@";
+
+/* Clock position format, medium: {hours} o’clock */
+"CLOCK_FMT_MEDIUM" = "שעה %@";
+
+/* Clock position format, short: {hours}:00 */
+"CLOCK_FMT_SHORT" = "%@:00";
+
+/* East, long */
+"COMPASS_E_LONG" = "מזרח";
+
+/* East, short */
+"COMPASS_E_SHORT" = "מז";
+
+/* East by north, long */
+"COMPASS_EbN_LONG" = "east by north";
+
+/* East by north, short */
+"COMPASS_EbN_SHORT" = "EbN";
+
+/* East by south, long */
+"COMPASS_EbS_LONG" = "east by south";
+
+/* East by south, short */
+"COMPASS_EbS_SHORT" = "EbS";
+
+/* East-northeast, long */
+"COMPASS_ENE_LONG" = "מזרח-צפון מזרח";
+
+/* East-northeast, short */
+"COMPASS_ENE_SHORT" = "מז-צ-מז";
+
+/* East-southeast, long */
+"COMPASS_ESE_LONG" = "מזרח-דרום מזרח";
+
+/* East-southeast, short */
+"COMPASS_ESE_SHORT" = "מז-ד-מז";
+
+/* North, long */
+"COMPASS_N_LONG" = "צפון";
+
+/* North, short */
+"COMPASS_N_SHORT" = "צ";
+
+/* North by east, long */
+"COMPASS_NbE_LONG" = "north by east";
+
+/* North by east, short */
+"COMPASS_NbE_SHORT" = "NbE";
+
+/* North by west, long */
+"COMPASS_NbW_LONG" = "north by west";
+
+/* North by west, short */
+"COMPASS_NbW_SHORT" = "NbW";
+
+/* Northeast, long */
+"COMPASS_NE_LONG" = "צפון מזרח";
+
+/* Northeast, short */
+"COMPASS_NE_SHORT" = "צ-מז";
+
+/* Northeast by east, long */
+"COMPASS_NEbE_LONG" = "northeast by east";
+
+/* Northeast by east, short */
+"COMPASS_NEbE_SHORT" = "NEbE";
+
+/* Northeast by north, long */
+"COMPASS_NEbN_LONG" = "northeast by north";
+
+/* Northeast by north, short */
+"COMPASS_NEbN_SHORT" = "NEbN";
+
+/* North-northeast, long */
+"COMPASS_NNE_LONG" = "צפון-צפון מזרח";
+
+/* North-northeast, short */
+"COMPASS_NNE_SHORT" = "צ-צ-מז";
+
+/* North-northwest, long */
+"COMPASS_NNW_LONG" = "צפון-צפון מערב";
+
+/* North-northwest, short */
+"COMPASS_NNW_SHORT" = "צ-צ-מע";
+
+/* Northwest, long */
+"COMPASS_NW_LONG" = "צפון מערב";
+
+/* Northwest, short */
+"COMPASS_NW_SHORT" = "צ-מע";
+
+/* Northwest by north, long */
+"COMPASS_NWbN_LONG" = "northwest by north";
+
+/* Northwest by north, short */
+"COMPASS_NWbN_SHORT" = "NWbN";
+
+/* Northwest by west, long */
+"COMPASS_NWbW_LONG" = "northwest by west";
+
+/* Northwest by west, short */
+"COMPASS_NWbW_SHORT" = "NWbW";
+
+/* South, long */
+"COMPASS_S_LONG" = "דרום";
+
+/* South, short */
+"COMPASS_S_SHORT" = "ד";
+
+/* South by east, long */
+"COMPASS_SbE_LONG" = "south by east";
+
+/* South by east, short */
+"COMPASS_SbE_SHORT" = "SbE";
+
+/* South by west, long */
+"COMPASS_SbW_LONG" = "south by west";
+
+/* South by west, short */
+"COMPASS_SbW_SHORT" = "SbW";
+
+/* Southeast, long */
+"COMPASS_SE_LONG" = "דרום מזרח";
+
+/* Southeast, short */
+"COMPASS_SE_SHORT" = "ד-מז";
+
+/* Southeast by east, long */
+"COMPASS_SEbE_LONG" = "southeast by east";
+
+/* Southeast by east, short */
+"COMPASS_SEbE_SHORT" = "SEbE";
+
+/* Southeast by south, long */
+"COMPASS_SEbS_LONG" = "southeast by south";
+
+/* Southeast by south, short */
+"COMPASS_SEbS_SHORT" = "SEbS";
+
+/* South-southeast, long */
+"COMPASS_SSE_LONG" = "דרום-דרום מזרח";
+
+/* South-southeast, short */
+"COMPASS_SSE_SHORT" = "ד-ד-מז";
+
+/* South-southwest, long */
+"COMPASS_SSW_LONG" = "דרום-דרום מערב";
+
+/* South-southwest, short */
+"COMPASS_SSW_SHORT" = "ד-ד-מע";
+
+/* Southwest, long */
+"COMPASS_SW_LONG" = "דרום מערב";
+
+/* Southwest, short */
+"COMPASS_SW_SHORT" = "ד-מע";
+
+/* Southwest by south, long */
+"COMPASS_SWbS_LONG" = "southwest by south";
+
+/* Southwest by south, short */
+"COMPASS_SWbS_SHORT" = "SWbS";
+
+/* Southwest by west, long */
+"COMPASS_SWbW_LONG" = "southwest by west";
+
+/* Southwest by west, short */
+"COMPASS_SWbW_SHORT" = "SWbW";
+
+/* West, long */
+"COMPASS_W_LONG" = "מערב";
+
+/* West, short */
+"COMPASS_W_SHORT" = "מע";
+
+/* West by north, long */
+"COMPASS_WbN_LONG" = "west by north";
+
+/* West by north, short */
+"COMPASS_WbN_SHORT" = "WbN";
+
+/* West by south, long */
+"COMPASS_WbS_LONG" = "west by south";
+
+/* West by south, short */
+"COMPASS_WbS_SHORT" = "WbS";
+
+/* West-northwest, long */
+"COMPASS_WNW_LONG" = "מערב-צפון מערב";
+
+/* West-northwest, short */
+"COMPASS_WNW_SHORT" = "מע-צ-מע";
+
+/* West-southwest, long */
+"COMPASS_WSW_LONG" = "מערב-דרום מערב";
+
+/* West-southwest, short */
+"COMPASS_WSW_SHORT" = "מע-ד-מע";
+
+/* Degrees format, long */
+"COORD_DEG_LONG" = "%d מעלה(ות)";
+
+/* Degrees format, medium: {degrees} */
+"COORD_DEG_MEDIUM" = "%d°";
+
+/* Degrees format, short: {degrees} */
+"COORD_DEG_SHORT" = "%d°";
+
+/* Coordinate format, long: {degrees}{minutes} */
+"COORD_DM_LONG" = "%1$@ ו %2$@";
+
+/* Coordinate format, medium: {degrees}{minutes} */
+"COORD_DM_MEDIUM" = "%1$@%2$@";
+
+/* Coordinate format, short: {degrees}{minutes} */
+"COORD_DM_SHORT" = "%1$@%2$@";
+
+/* Coordinate format, long: {degrees}{minutes}{seconds} */
+"COORD_DMS_LONG" = "%1$@, %2$@, ו %3$@";
+
+/* Coordinate format, medium: {degrees}{minutes}{seconds} */
+"COORD_DMS_MEDIUM" = "%1$@%2$@%3$@";
+
+/* Coordinate format, short: {degrees}{minutes}{seconds} */
+"COORD_DMS_SHORT" = "%1$@%2$@%3$@";
+
+/* East longitude format, long: {longitude} */
+"COORD_E_LONG" = "%@ מזרחה";
+
+/* East longitude format, medium: {longitude} */
+"COORD_E_MEDIUM" = "%@ מזרחה";
+
+/* East longitude format, short: {longitude} */
+"COORD_E_SHORT" = "%@מז";
+
+/* Coordinate pair format, long: {latitude}, {longitude} */
+"COORD_FMT_LONG" = "%1$@ על %2$@";
+
+/* Coordinate pair format, medium: {latitude}, {longitude} */
+"COORD_FMT_MEDIUM" = "%1$@, %2$@";
+
+/* Coordinate pair format, short: {latitude}, {longitude} */
+"COORD_FMT_SHORT" = "%1$@, %2$@";
+
+/* Minutes format, long */
+"COORD_MIN_LONG" = "%d דקה(ות)";
+
+/* Minutes format, medium: {minutes} */
+"COORD_MIN_MEDIUM" = "%d′";
+
+/* Minutes format, short: {minutes} */
+"COORD_MIN_SHORT" = "%d′";
+
+/* North latitude format, long: {latitude} */
+"COORD_N_LONG" = "%@ צפונה";
+
+/* North latitude format, medium: {latitude} */
+"COORD_N_MEDIUM" = "%@ צפונה";
+
+/* North latitude format, short: {latitude} */
+"COORD_N_SHORT" = "%@צ";
+
+/* South latitude format, long: {latitude} */
+"COORD_S_LONG" = "%@ דרומה";
+
+/* South latitude format, medium: {latitude} */
+"COORD_S_MEDIUM" = "%@ דרומה";
+
+/* South latitude format, short: {latitude} */
+"COORD_S_SHORT" = "%@ד";
+
+/* Seconds format, long */
+"COORD_SEC_LONG" = "%d שניה(ות)";
+
+/* Seconds format, medium: {seconds} */
+"COORD_SEC_MEDIUM" = "%d″";
+
+/* Seconds format, short: {seconds} */
+"COORD_SEC_SHORT" = "%d″";
+
+/* West longitude format, long: {longitude} */
+"COORD_W_LONG" = "%@ מערב";
+
+/* West longitude format, medium: {longitude} */
+"COORD_W_MEDIUM" = "%@ מערב";
+
+/* West longitude format, short: {longitude} */
+"COORD_W_SHORT" = "%@מע";
+
+/* OpenStreetMap full name attribution */
+"OSM_FULL_NAME" = "OpenStreetMap";
+
+/* OpenStreetMap short name attribution */
+"OSM_SHORT_NAME" = "OSM";
+
diff --git a/platform/darwin/resources/ja.lproj/Foundation.strings b/platform/darwin/resources/ja.lproj/Foundation.strings
index 52dda1557f..3588f38e48 100644
--- a/platform/darwin/resources/ja.lproj/Foundation.strings
+++ b/platform/darwin/resources/ja.lproj/Foundation.strings
Binary files differ
diff --git a/platform/darwin/resources/lt.lproj/Foundation.strings b/platform/darwin/resources/lt.lproj/Foundation.strings
index 1151a559bd..2bd0baa210 100644
--- a/platform/darwin/resources/lt.lproj/Foundation.strings
+++ b/platform/darwin/resources/lt.lproj/Foundation.strings
Binary files differ
diff --git a/platform/darwin/resources/pt-BR.lproj/Foundation.strings b/platform/darwin/resources/pt-BR.lproj/Foundation.strings
index bf0e126d79..331b61dd77 100644
--- a/platform/darwin/resources/pt-BR.lproj/Foundation.strings
+++ b/platform/darwin/resources/pt-BR.lproj/Foundation.strings
Binary files differ
diff --git a/platform/darwin/resources/pt-PT.lproj/Foundation.stringsdict b/platform/darwin/resources/pt-PT.lproj/Foundation.stringsdict
new file mode 100644
index 0000000000..e99e86d98d
--- /dev/null
+++ b/platform/darwin/resources/pt-PT.lproj/Foundation.stringsdict
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>COORD_DEG_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@degrees@</string>
+ <key>degrees</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d grau</string>
+ <key>other</key>
+ <string>%d graus</string>
+ </dict>
+ </dict>
+ <key>COORD_MIN_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@minutes@</string>
+ <key>minutes</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d minuto</string>
+ <key>other</key>
+ <string>%d minutos</string>
+ </dict>
+ </dict>
+ <key>COORD_SEC_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@seconds@</string>
+ <key>seconds</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d segundo</string>
+ <key>other</key>
+ <string>%d segundos</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/darwin/resources/ru.lproj/Foundation.strings b/platform/darwin/resources/ru.lproj/Foundation.strings
index f029952595..4842496377 100644
--- a/platform/darwin/resources/ru.lproj/Foundation.strings
+++ b/platform/darwin/resources/ru.lproj/Foundation.strings
Binary files differ
diff --git a/platform/darwin/resources/sv.lproj/Foundation.strings b/platform/darwin/resources/sv.lproj/Foundation.strings
index 4391ec7f95..e3e7f931a8 100644
--- a/platform/darwin/resources/sv.lproj/Foundation.strings
+++ b/platform/darwin/resources/sv.lproj/Foundation.strings
Binary files differ
diff --git a/platform/darwin/resources/uk.lproj/Foundation.strings b/platform/darwin/resources/uk.lproj/Foundation.strings
index d9d9ad32e1..ded065c564 100644
--- a/platform/darwin/resources/uk.lproj/Foundation.strings
+++ b/platform/darwin/resources/uk.lproj/Foundation.strings
Binary files differ
diff --git a/platform/darwin/resources/zh-Hans.lproj/Foundation.strings b/platform/darwin/resources/zh-Hans.lproj/Foundation.strings
index e69b65f2ac..0c57a70d8a 100644
--- a/platform/darwin/resources/zh-Hans.lproj/Foundation.strings
+++ b/platform/darwin/resources/zh-Hans.lproj/Foundation.strings
Binary files differ
diff --git a/platform/darwin/resources/zh-Hant.lproj/Foundation.strings b/platform/darwin/resources/zh-Hant.lproj/Foundation.strings
index 2fa92e1c6e..7946dcf7cd 100644
--- a/platform/darwin/resources/zh-Hant.lproj/Foundation.strings
+++ b/platform/darwin/resources/zh-Hant.lproj/Foundation.strings
Binary files differ
diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js
index 4ee86e65da..c7b54b326a 100644..100755
--- a/platform/darwin/scripts/generate-style-code.js
+++ b/platform/darwin/scripts/generate-style-code.js
@@ -1,3 +1,4 @@
+#!/usr/bin/env node
'use strict';
const fs = require('fs');
@@ -11,7 +12,7 @@ const cocoaConventions = require('./style-spec-cocoa-conventions-v8.json');
const prefix = 'MGL';
const suffix = 'StyleLayer';
-let spec = _.merge(require('../../../mapbox-gl-js/src/style-spec/reference/v8'), require('./style-spec-overrides-v8.json'));
+let spec = _.merge(require('../../../scripts/style-spec'), require('./style-spec-overrides-v8.json'));
// Rename properties and keep `original` for use with setters and getters
_.forOwn(cocoaConventions, function (properties, kind) {
@@ -27,8 +28,10 @@ _.forOwn(cocoaConventions, function (properties, kind) {
delete spec[kind][oldName];
spec[kind][newName] = property;
- // Update requirements in other properties.
- let updateRequirements = function (property, name) {
+ // Update cross-references to this property in other properties'
+ // documentation and requirements.
+ let renameCrossReferences = function (property, name) {
+ property.doc = property.doc.replace(new RegExp('`' + oldName + '`', 'g'), '`' + newName + '`');
let requires = property.requires || [];
for (let i = 0; i < requires.length; i++) {
if (requires[i] === oldName) {
@@ -45,8 +48,8 @@ _.forOwn(cocoaConventions, function (properties, kind) {
}
}
};
- _.forOwn(spec[kind.replace(/^layout_/, 'paint_')], updateRequirements);
- _.forOwn(spec[kind.replace(/^paint_/, 'layout_')], updateRequirements);
+ _.forOwn(spec[kind.replace(/^layout_/, 'paint_')], renameCrossReferences);
+ _.forOwn(spec[kind.replace(/^paint_/, 'layout_')], renameCrossReferences);
})
});
@@ -92,37 +95,42 @@ global.testImplementation = function (property, layerType, isFunction) {
return `layer.${objCName(property)} = [MGLRuntimeStylingHelper ${helperMsg}];`;
};
-global.objCTestValue = function (property, layerType, indent) {
+global.objCTestValue = function (property, layerType, arraysAsStructs, indent) {
let propertyName = originalPropertyName(property);
switch (property.type) {
case 'boolean':
- return property.default ? '@NO' : '@YES';
+ return property.default ? '@"false"' : '@"true"';
case 'number':
- return '@0xff';
+ return '@"0xff"';
case 'string':
- return `@"${_.startCase(propertyName)}"`;
+ return `@"'${_.startCase(propertyName)}'"`;
case 'enum':
- let type = objCType(layerType, property.name);
- let value = `${type}${camelize(_.last(_.keys(property.values)))}`;
- return `[NSValue valueWith${type}:${value}]`;
+ return `@"'${_.last(_.keys(property.values))}'"`;
case 'color':
- return '[MGLColor redColor]';
+ return '@"%@", [MGLColor redColor]';
case 'array':
switch (arrayType(property)) {
case 'dasharray':
- return '@[@1, @2]';
+ return '@"{1, 2}"';
case 'font':
- return `@[@"${_.startCase(propertyName)}", @"${_.startCase(_.reverse(propertyName.split('')).join(''))}"]`;
+ return `@"{'${_.startCase(propertyName)}', '${_.startCase(_.reverse(propertyName.split('')).join(''))}'}"`;
case 'padding': {
- let iosValue = '[NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(1, 1, 1, 1)]'.indent(indent * 4);
- let macosValue = '[NSValue valueWithEdgeInsets:NSEdgeInsetsMake(1, 1, 1, 1)]'.indent(indent * 4);
- return `\n#if TARGET_OS_IPHONE\n${iosValue}\n#else\n${macosValue}\n#endif\n${''.indent((indent - 1) * 4)}`;
+ if (arraysAsStructs) {
+ let iosValue = '[NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(1, 1, 1, 1)]'.indent(indent * 4);
+ let macosValue = '[NSValue valueWithEdgeInsets:NSEdgeInsetsMake(1, 1, 1, 1)]'.indent(indent * 4);
+ return `@"%@",\n#if TARGET_OS_IPHONE\n${iosValue}\n#else\n${macosValue}\n#endif\n${''.indent((indent - 1) * 4)}`;
+ }
+ return '@"{1, 1, 1, 1}"';
}
case 'offset':
- case 'translate':
- let iosValue = '[NSValue valueWithCGVector:CGVectorMake(1, 1)]'.indent(indent * 4);
- let macosValue = '[NSValue valueWithMGLVector:CGVectorMake(1, -1)]'.indent(indent * 4);
- return `\n#if TARGET_OS_IPHONE\n${iosValue}\n#else\n${macosValue}\n#endif\n${''.indent((indent - 1) * 4)}`;
+ case 'translate': {
+ if (arraysAsStructs) {
+ let iosValue = '[NSValue valueWithCGVector:CGVectorMake(1, 1)]'.indent(indent * 4);
+ let macosValue = '[NSValue valueWithMGLVector:CGVectorMake(1, -1)]'.indent(indent * 4);
+ return `@"%@",\n#if TARGET_OS_IPHONE\n${iosValue}\n#else\n${macosValue}\n#endif\n${''.indent((indent - 1) * 4)}`;
+ }
+ return '@"{1, 1}"';
+ }
default:
throw new Error(`unknown array type for ${property.name}`);
}
@@ -245,6 +253,13 @@ global.propertyDoc = function (propertyName, property, layerType, kind) {
// Format everything else: our property name & its possible values.
// Requires symbols to be surrounded by backticks.
doc = doc.replace(/`(.+?)`/g, function (m, symbol, offset, str) {
+ if (kind === 'enum') {
+ let layoutProperties = spec[`layout_${layerType}`] || [];
+ let paintProperties = spec[`paint_${layerType}`] || [];
+ if (symbol in layoutProperties || symbol in paintProperties) {
+ return '`MGL' + camelize(layerType) + 'StyleLayer.' + camelizeWithLeadingLowercase(symbol) + '`';
+ }
+ }
if ('values' in property && Object.keys(property.values).indexOf(symbol) !== -1) {
let objCType = global.objCType(layerType, property.name);
return '`' + `${objCType}${camelize(symbol)}` + '`';
@@ -284,29 +299,34 @@ global.propertyDoc = function (propertyName, property, layerType, kind) {
}
doc += `\n\nThis attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#${anchor}"><code>${property.original}</code></a> layout property in the Mapbox Style Specification.`;
}
- doc += '\n\nYou can set this property to an instance of:\n\n' +
- '* `MGLConstantStyleValue`\n';
- if (property["property-function"]) {
- doc += '* `MGLCameraStyleFunction` with an interpolation mode of:\n' +
- ' * `MGLInterpolationModeExponential`\n' +
- ' * `MGLInterpolationModeInterval`\n' +
- '* `MGLSourceStyleFunction` with an interpolation mode of:\n' +
- ' * `MGLInterpolationModeExponential`\n' +
- ' * `MGLInterpolationModeInterval`\n' +
- ' * `MGLInterpolationModeCategorical`\n' +
- ' * `MGLInterpolationModeIdentity`\n' +
- '* `MGLCompositeStyleFunction` with an interpolation mode of:\n' +
- ' * `MGLInterpolationModeExponential`\n' +
- ' * `MGLInterpolationModeInterval`\n' +
- ' * `MGLInterpolationModeCategorical`\n';
- } else {
- if (property.function === "interpolated") {
- doc += '* `MGLCameraStyleFunction` with an interpolation mode of:\n' +
- ' * `MGLInterpolationModeExponential`\n' +
- ' * `MGLInterpolationModeInterval`\n';
+ doc += '\n\nYou can set this property to an expression containing any of the following:\n\n';
+ doc += `* Constant ${describeType(property)} values`;
+ if ('minimum' in property) {
+ if ('maximum' in property) {
+ doc += ` between ${formatNumber(property.minimum)} and ${formatNumber(property.maximum)} inclusive`;
} else {
- doc += '* `MGLCameraStyleFunction` with an interpolation mode of `MGLInterpolationModeInterval`\n';
+ doc += ` no less than ${formatNumber(property.minimum)}`;
}
+ } else if ('maximum' in property) {
+ doc += ` no greater than ${formatNumber(property.maximum)}`;
+ }
+ doc += '\n';
+ if (property.type === 'enum') {
+ doc += '* Any of the following constant string values:\n';
+ doc += Object.keys(property.values).map(value => ' * `' + value + '`: ' + property.values[value].doc).join('\n') + '\n';
+ }
+ doc += '* Predefined functions, including mathematical and string operators\n' +
+ '* Conditional expressions\n' +
+ '* Variable assignments and references to assigned variables\n';
+ const inputVariable = property.name === 'heatmap-color' ? '$heatmapDensity' : '$zoomLevel';
+ if (property["property-function"]) {
+ doc += `* Interpolation and step functions applied to the \`${inputVariable}\` variable and/or feature attributes\n`;
+ } else if (property.function === "interpolated") {
+ doc += `* Interpolation and step functions applied to the \`${inputVariable}\` variable\n\n` +
+ 'This property does not support applying interpolation or step functions to feature attributes.';
+ } else {
+ doc += `* Step functions applied to the \`${inputVariable}\` variable\n\n` +
+ `This property does not support applying interpolation functions to the \`${inputVariable}\` variable or applying interpolation or step functions to feature attributes.`;
}
}
return doc;
@@ -320,7 +340,7 @@ global.propertyReqs = function (property, propertiesByName, type) {
return '`' + camelizeWithLeadingLowercase(req['!']) + '` is set to `nil`';
} else {
let name = Object.keys(req)[0];
- return '`' + camelizeWithLeadingLowercase(name) + '` is set to an `MGLStyleValue` object containing ' + describeValue(req[name], propertiesByName[name], type);
+ return '`' + camelizeWithLeadingLowercase(name) + '` is set to an expression that evaluates to ' + describeValue(req[name], propertiesByName[name], type);
}
}).join(', and ') + '. Otherwise, it is ignored.';
};
@@ -335,12 +355,55 @@ global.parseColor = function (str) {
};
};
+global.describeType = function (property) {
+ switch (property.type) {
+ case 'boolean':
+ return 'Boolean';
+ case 'number':
+ return 'numeric';
+ case 'string':
+ return 'string';
+ case 'enum':
+ return '`MGL' + camelize(property.name) + '`';
+ case 'color':
+ return '`UIColor`';
+ case 'array':
+ switch (arrayType(property)) {
+ case 'padding':
+ return '`UIEdgeInsets`';
+ case 'offset':
+ case 'translate':
+ return '`CGVector`';
+ case 'position':
+ return '`MGLSphericalPosition`';
+ default:
+ return 'array';
+ }
+ break;
+ default:
+ throw new Error(`unknown type for ${property.name}`);
+ }
+}
+
global.describeValue = function (value, property, layerType) {
+ if (Array.isArray(value) && property.type !== 'array' && property.type !== 'enum') {
+ switch (value[0]) {
+ case 'interpolate': {
+ let curveType = value[1][0];
+ let minimum = describeValue(value[3 + value.length % 2], property, layerType);
+ let maximum = describeValue(_.last(value), property, layerType);
+ return `${curveType.match(/^[aeiou]/i) ? 'an' : 'a'} ${curveType} interpolation expression ranging from ${minimum} to ${maximum}`;
+ }
+ default:
+ throw new Error(`No description available for ${value[0]} expression in ${property.name} of ${layerType}.`);
+ }
+ }
+
switch (property.type) {
case 'boolean':
- return 'an `NSNumber` object containing ' + (value ? '`YES`' : '`NO`');
+ return value ? '`YES`' : '`NO`';
case 'number':
- return 'an `NSNumber` object containing the float `' + value + '`';
+ return 'the float ' + formatNumber(value);
case 'string':
if (value === '') {
return 'the empty string';
@@ -349,21 +412,18 @@ global.describeValue = function (value, property, layerType) {
case 'enum':
let displayValue;
if (Array.isArray(value)) {
- let separator = (value.length === 2) ? ' ' : ', ';
- displayValue = value.map((possibleValue, i) => {
- let conjunction = '';
- if (value.length === 2 && i === 0) conjunction = 'either ';
- if (i === value.length - 1) conjunction = 'or ';
- let objCType = global.objCType(layerType, property.name);
- return `${conjunction}\`${objCType}${camelize(possibleValue)}\``;
- }).join(separator);
- } else if (property['light-property']) {
- displayValue = `\`${prefix}Light${camelize(property.name)}${camelize(value)}\``;
+ let separator = (value.length === 2) ? ' ' : ', ';
+ displayValue = value.map((possibleValue, i) => {
+ let conjunction = '';
+ if (value.length === 2 && i === 0) conjunction = 'either ';
+ if (i === value.length - 1) conjunction = 'or ';
+ let objCType = global.objCType(layerType, property.name);
+ return `${conjunction}\`${objCType}${camelize(possibleValue)}\``;
+ }).join(separator);
} else {
- let objCType = global.objCType(layerType, property.name);
- displayValue = `\`${objCType}${camelize(value)}\``;
+ displayValue = `\`${value}\``;
}
- return `an \`NSValue\` object containing ${displayValue}`;
+ return displayValue;
case 'color':
let color = parseColor(value);
if (!color) {
@@ -378,7 +438,7 @@ global.describeValue = function (value, property, layerType) {
if (color.r === 1 && color.g === 1 && color.b === 1 && color.a === 1) {
return '`UIColor.whiteColor`';
}
- return 'a `UIColor`' + ` object whose RGB value is ${color.r}, ${color.g}, ${color.b} and whose alpha value is ${color.a}`;
+ return 'a `UIColor`' + ` object whose RGB value is ${formatNumber(color.r)}, ${formatNumber(color.g)}, ${formatNumber(color.b)} and whose alpha value is ${formatNumber(color.a)}`;
case 'array':
let units = property.units || '';
if (units) {
@@ -389,12 +449,12 @@ global.describeValue = function (value, property, layerType) {
if (value[0] === 0 && value[1] === 0 && value[2] === 0 && value[3] === 0) {
return 'an `NSValue` object containing `UIEdgeInsetsZero`';
}
- return 'an `NSValue` object containing a `UIEdgeInsets` struct set to' + ` ${value[0]}${units} on the top, ${value[3]}${units} on the left, ${value[2]}${units} on the bottom, and ${value[1]}${units} on the right`;
+ return 'an `NSValue` object containing a `UIEdgeInsets` struct set to' + ` ${formatNumber(value[0])}${units} on the top, ${formatNumber(value[3])}${units} on the left, ${formatNumber(value[2])}${units} on the bottom, and ${formatNumber(value[1])}${units} on the right`;
case 'offset':
case 'translate':
- return 'an `NSValue` object containing a `CGVector` struct set to' + ` ${value[0]}${units} rightward and ${value[1]}${units} downward`;
+ return 'an `NSValue` object containing a `CGVector` struct set to' + ` ${formatNumber(value[0])}${units} rightward and ${formatNumber(value[1])}${units} downward`;
case 'position':
- return 'an `MGLSphericalPosition` struct set to' + ` ${value[0]} radial, ${value[1]} azimuthal and ${value[2]} polar`;
+ return 'an `MGLSphericalPosition` struct set to' + ` ${formatNumber(value[0])} radial, ${formatNumber(value[1])} azimuthal and ${formatNumber(value[2])} polar`;
default:
return 'the array `' + value.join('`, `') + '`';
}
@@ -403,8 +463,16 @@ global.describeValue = function (value, property, layerType) {
}
};
+global.formatNumber = function (num) {
+ return num.toLocaleString().replace('-', '\u2212');
+}
+
global.propertyDefault = function (property, layerType) {
- return 'an `MGLStyleValue` object containing ' + describeValue(property.default, property, layerType);
+ if (property.name === 'heatmap-color') {
+ return 'an expression that evaluates to a rainbow color scale from blue to red';
+ } else {
+ return 'an expression that evaluates to ' + describeValue(property.default, property, layerType);
+ }
};
global.originalPropertyName = function (property) {
@@ -558,15 +626,15 @@ const layerH = ejs.compile(fs.readFileSync('platform/darwin/src/MGLStyleLayer.h.
const layerM = ejs.compile(fs.readFileSync('platform/darwin/src/MGLStyleLayer.mm.ejs', 'utf8'), { strict: true});
const testLayers = ejs.compile(fs.readFileSync('platform/darwin/test/MGLStyleLayerTests.mm.ejs', 'utf8'), { strict: true});
const forStyleAuthorsMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/For Style Authors.md.ejs', 'utf8'), { strict: true });
-const ddsGuideMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/Using Style Functions at Runtime.md.ejs', 'utf8'), { strict: true });
+const ddsGuideMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/Migrating to Expressions.md.ejs', 'utf8'), { strict: true });
const templatesMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/Tile URL Templates.md.ejs', 'utf8'), { strict: true });
const lightH = ejs.compile(fs.readFileSync('platform/darwin/src/MGLLight.h.ejs', 'utf8'), {strict: true});
const lightM = ejs.compile(fs.readFileSync('platform/darwin/src/MGLLight.mm.ejs', 'utf8'), {strict: true});
const testLight = ejs.compile(fs.readFileSync('platform/darwin/test/MGLLightTest.mm.ejs', 'utf8'), { strict: true});
-fs.writeFileSync(`platform/darwin/src/MGLLight.h`, duplicatePlatformDecls(lightH({ properties: lightProperties, doc: lightDoc, type: lightType })));
-fs.writeFileSync(`platform/darwin/src/MGLLight.mm`, lightM({ properties: lightProperties, doc: lightDoc, type: lightType }));
-fs.writeFileSync(`platform/darwin/test/MGLLightTest.mm`, testLight({ properties: lightProperties, doc: lightDoc, type: lightType }));
+writeIfModified(`platform/darwin/src/MGLLight.h`, duplicatePlatformDecls(lightH({ properties: lightProperties, doc: lightDoc, type: lightType })));
+writeIfModified(`platform/darwin/src/MGLLight.mm`, lightM({ properties: lightProperties, doc: lightDoc, type: lightType }));
+writeIfModified(`platform/darwin/test/MGLLightTest.mm`, testLight({ properties: lightProperties, doc: lightDoc, type: lightType }));
const layers = _(spec.layer.type.values).map((value, layerType) => {
@@ -596,13 +664,13 @@ function duplicatePlatformDecls(src) {
// Look for a documentation comment that contains “MGLColor” or “UIColor”
// and the subsequent function, method, or property declaration. Try not to
// match greedily.
- return src.replace(/(\/\*\*(?:\*[^\/]|[^*])*?\*\/)(\s*[^;]+?\b(?:MGL|NS|UI)(?:Color|EdgeInsets(?:Zero)?)\b[^;]+?;)/g,
+ return src.replace(/(\/\*\*(?:\*[^\/]|[^*])*?\b(?:MGL|NS|UI)Color\b[\s\S]*?\*\/)(\s*.+?;)/g,
(match, comment, decl) => {
- let macosComment = comment.replace(/\b(?:MGL|UI)(Color|EdgeInsets(?:Zero)?)\b/g, 'NS$1')
+ let macosComment = comment.replace(/\b(?:MGL|UI)Color\b/g, 'NSColor')
// Use the correct indefinite article.
- .replace(/\ba(\s+`?NS(?:Color|EdgeInsets))\b/gi, 'an$1');
- let iosDecl = decl.replace(/\bMGL(Color|EdgeInsets)\b/g, 'UI$1');
- let macosDecl = decl.replace(/\b(?:MGL|UI)(Color|EdgeInsets)\b/g, 'NS$1');
+ .replace(/\ba(\s+`?NSColor)\b/gi, 'an$1');
+ let iosDecl = decl.replace(/\bMGLColor\b/g, 'UIColor');
+ let macosDecl = decl.replace(/\b(?:MGL|UI)Color\b/g, 'NSColor');
return `\
#if TARGET_OS_IPHONE
${comment}${iosDecl}
@@ -639,9 +707,9 @@ for (var layer of layers) {
renamedPropertiesByLayerType[layer.type] = renamedProperties;
}
- fs.writeFileSync(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.h`, duplicatePlatformDecls(layerH(layer)));
- fs.writeFileSync(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.mm`, layerM(layer));
- fs.writeFileSync(`platform/darwin/test/${prefix}${camelize(layer.type)}${suffix}Tests.mm`, testLayers(layer));
+ writeIfModified(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.h`, duplicatePlatformDecls(layerH(layer)));
+ writeIfModified(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.mm`, layerM(layer));
+ writeIfModified(`platform/darwin/test/${prefix}${camelize(layer.type)}${suffix}Tests.mm`, testLayers(layer));
}
// Extract examples for guides from unit tests.
@@ -679,25 +747,25 @@ global.guideExample = function (guide, exampleId, os) {
return '```swift\n' + example + '\n```';
};
-fs.writeFileSync(`platform/ios/docs/guides/For Style Authors.md`, forStyleAuthorsMD({
+writeIfModified(`platform/ios/docs/guides/For Style Authors.md`, forStyleAuthorsMD({
os: 'iOS',
renamedProperties: renamedPropertiesByLayerType,
layers: layers,
}));
-fs.writeFileSync(`platform/macos/docs/guides/For Style Authors.md`, forStyleAuthorsMD({
+writeIfModified(`platform/macos/docs/guides/For Style Authors.md`, forStyleAuthorsMD({
os: 'macOS',
renamedProperties: renamedPropertiesByLayerType,
layers: layers,
}));
-fs.writeFileSync(`platform/ios/docs/guides/Using Style Functions at Runtime.md`, ddsGuideMD({
+writeIfModified(`platform/ios/docs/guides/Migrating to Expressions.md`, ddsGuideMD({
os: 'iOS',
}));
-fs.writeFileSync(`platform/macos/docs/guides/Using Style Functions at Runtime.md`, ddsGuideMD({
+writeIfModified(`platform/macos/docs/guides/Migrating to Expressions.md`, ddsGuideMD({
os: 'macOS',
}));
-fs.writeFileSync(`platform/ios/docs/guides/Tile URL Templates.md`, templatesMD({
+writeIfModified(`platform/ios/docs/guides/Tile URL Templates.md`, templatesMD({
os: 'iOS',
}));
-fs.writeFileSync(`platform/macos/docs/guides/Tile URL Templates.md`, templatesMD({
+writeIfModified(`platform/macos/docs/guides/Tile URL Templates.md`, templatesMD({
os: 'macOS',
}));
diff --git a/platform/darwin/scripts/style-spec-overrides-v8.json b/platform/darwin/scripts/style-spec-overrides-v8.json
index 67a6641fe7..d47b13cdb2 100644
--- a/platform/darwin/scripts/style-spec-overrides-v8.json
+++ b/platform/darwin/scripts/style-spec-overrides-v8.json
@@ -9,22 +9,28 @@
"type": {
"values": {
"fill": {
- "doc": "An `MGLFillStyleLayer` is a style layer that renders one or more filled (and optionally stroked) polygons on the map.\n\nUse 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."
+ "doc": "An `MGLFillStyleLayer` is a style layer that renders one or more filled (and optionally stroked) polygons on the map.\n\nUse a fill style layer to configure the visual appearance of polygon 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."
},
"fill-extrusion": {
- "doc": "An `MGLFillExtrusionStyleLayer` is a style layer that renders one or more 3D extruded polygons on the map.\n\nUse 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."
+ "doc": "An `MGLFillExtrusionStyleLayer` is a style layer that renders one or more 3D extruded polygons on the map.\n\nUse a fill-extrusion style layer to configure the visual appearance of polygon 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."
},
"line": {
- "doc": "An `MGLLineStyleLayer` is a style layer that renders one or more stroked polylines on the map.\n\nUse 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."
+ "doc": "An `MGLLineStyleLayer` is a style layer that renders one or more stroked polylines on the map.\n\nUse a line style layer to configure the visual appearance of polyline or 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."
},
"symbol": {
- "doc": "An `MGLSymbolStyleLayer` is a style layer that renders icon and text labels at points or along lines on the map.\n\nUse 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."
+ "doc": "An `MGLSymbolStyleLayer` is a style layer that renders icon and text labels at points or along lines on the map.\n\nUse 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."
},
"circle": {
- "doc": "An `MGLCircleStyleLayer` is a style layer that renders one or more filled circles on the map.\n\nUse 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.\n\nA 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, use many-sided regular polygons and configure their appearance using an `MGLFillStyleLayer` object."
+ "doc": "An `MGLCircleStyleLayer` is a style layer that renders one or more filled circles on the map.\n\nUse a circle style layer to configure the visual appearance of 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.\n\nA 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, use many-sided regular polygons and configure their appearance using an `MGLFillStyleLayer` object."
+ },
+ "heatmap": {
+ "doc": "An `MGLHeatmapStyleLayer` is a style layer that renders a <a href=\"https://en.wikipedia.org/wiki/Heat_map\">heatmap</a>.\n\nA 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. 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.\n\nConsider accompanying a heatmap style layer with an `MGLCircleStyleLayer` or `MGLSymbolStyleLayer` at high zoom levels. If you are unsure whether the point data in an `MGLShapeSource` is dense enough to warrant a heatmap, you can alternatively cluster the source using the `MGLShapeSourceOptionClustered` option and render the data using an `MGLCircleStyleLayer` or `MGLSymbolStyleLayer`."
},
"raster": {
- "doc": "An `MGLRasterStyleLayer` is a style layer that renders raster tiles on the map.\n\nUse a raster style layer to configure the color parameters of raster tiles loaded by an `MGLRasterSource` 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 href=\"https://www.mapbox.com/help/define-tileset/#raster-tilesets\">raster tile set</a> uploaded to Mapbox Studio, or a raster map authored in <a href=\"https://tilemill-project.github.io/tilemill/\">TileMill</a>, the classic Mapbox Editor, or Mapbox Studio Classic."
+ "doc": "An `MGLRasterStyleLayer` is a style layer that renders georeferenced raster imagery on the map, especially raster tiles.\n\nUse a raster style layer to configure the color parameters of raster tiles 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 href=\"https://www.mapbox.com/help/define-tileset/#raster-tilesets\">raster tile set</a> uploaded to Mapbox Studio, or a raster map authored in <a href=\"https://tilemill-project.github.io/tilemill/\">TileMill</a>, the classic Mapbox Editor, or Mapbox Studio Classic.\n\nRaster images may also be used as icons or patterns in a style layer. To register an image for use as an icon or pattern, use the `-[MGLStyle setImage:forName:]` method. To configure a point annotation’s image, use the `MGLAnnotationImage` class."
+ },
+ "hillshade": {
+ "doc": "An `MGLHillshadeStyleLayer` is a style layer that renders raster <a href=\"https://en.wikipedia.org/wiki/Digital_elevation_model\">digital elevation model</a> (DEM) tiles on the map.\n\nUse a hillshade style layer to configure the color parameters of raster tiles loaded by an `MGLRasterDEMSource` object. For example, you could use a hillshade style layer to render <a href=\"https://www.mapbox.com/help/access-elevation-data/#mapbox-terrain-rgb\">Mapbox Terrain-RGB</a> data.\n\nTo 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 `MGLVectorTileSource` object in conjunction with several `MGLFillStyleLayer` objects."
},
"background": {
"doc": "An `MGLBackgroundStyleLayer` is a style layer that covers the entire map. Use a background style layer to configure a color or pattern to show below all other map content. If the style’s other layers use the Mapbox Streets source, the background style layer is responsible for drawing land, whereas the oceans and other bodies of water are drawn by `MGLFillStyleLayer` objects.\n\nA background style layer is typically the bottommost layer in a style, because it covers the entire map and can occlude any layers below it. You can therefore access it by getting the last item in the `MGLStyle.layers` array.\n\nIf the background style layer is transparent or omitted from the style, any portion of the map view that does not show another style layer is transparent."
@@ -39,6 +45,12 @@
"icon-offset": {
"doc": "Offset distance of icon from its anchor."
},
+ "icon-image": {
+ "doc": "Name of a style image to use for drawing an image background.\n\nUse the `+[MGLStyle setImage:forName:]` method to associate an image with a name that you can set this property to.\n\nWithin 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."
+ },
+ "text-field": {
+ "doc": "Value to use for a text label.\n\nWithin 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."
+ },
"text-font": {
"doc": "An array of font face names used to display the text.\n\nEach font name must be included in the `{fontstack}` portion of the JSON stylesheet’s <a href=\"https://www.mapbox.com/mapbox-gl-style-spec/#glyphs\"><code>glyphs</code></a> property. You can register a custom font when designing the style in Mapbox Studio. Fonts installed on the system are not used.\n\nThe first font named in the array is applied to the text. For each character in the text, if the first font lacks a glyph for the character, the next font is applied as a fallback, and so on."
},
@@ -70,6 +82,11 @@
"doc": "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 `fill-extrusion-opacity` to set layer opacityco."
}
},
+ "paint_heatmap": {
+ "heatmap-color": {
+ "doc": "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."
+ }
+ },
"paint_line": {
"line-pattern": {
"doc": "Name of image in style images to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512)."
@@ -105,4 +122,4 @@
"doc": "Distance that the text's anchor is moved from its original placement."
}
}
-} \ No newline at end of file
+}
diff --git a/platform/darwin/scripts/update-examples.js b/platform/darwin/scripts/update-examples.js
index d453c0e4ba..f87ed07288 100644..100755
--- a/platform/darwin/scripts/update-examples.js
+++ b/platform/darwin/scripts/update-examples.js
@@ -1,9 +1,12 @@
+#!/usr/bin/env node
'use strict';
const fs = require('fs');
const execFileSync = require('child_process').execFileSync;
const _ = require('lodash');
+require('../../../scripts/style-code');
+
const examplesSrc = fs.readFileSync('platform/darwin/test/MGLDocumentationExampleTests.swift', 'utf8');
// Regex extracts the following block
@@ -124,14 +127,7 @@ function completeExamples(os) {
}
// Write out the modified file contents.
- if (src === newSrc) {
- console.log('Skipping', path);
- } else {
- console.log('Updating', path);
- if (['0', 'false'].indexOf(process.env.DRY_RUN || '0') !== -1) {
- fs.writeFileSync(path, newSrc);
- }
- }
+ writeIfModified(path, newSrc)
});
});
}
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 7e55779d04..73da8ddd63 100644
--- a/platform/darwin/src/MGLAccountManager.m
+++ b/platform/darwin/src/MGLAccountManager.m
@@ -39,7 +39,7 @@
}
static dispatch_once_t onceToken;
static MGLAccountManager *_sharedManager;
- void (^setupBlock)() = ^{
+ void (^setupBlock)(void) = ^{
dispatch_once(&onceToken, ^{
_sharedManager = [[self alloc] init];
});
@@ -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 52a83fd18e..e8d6a203d0 100644
--- a/platform/darwin/src/MGLAttributionInfo.mm
+++ b/platform/darwin/src/MGLAttributionInfo.mm
@@ -16,7 +16,7 @@
@implementation MGLAttributionInfo
-+ (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosFromHTMLString:(nullable NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
++ (NSArray<MGLAttributionInfo *> *)attributionInfosFromHTMLString:(nullable NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
if (!htmlString) {
return @[];
}
@@ -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:
@@ -107,7 +112,7 @@
return infos;
}
-+ (NSAttributedString *)attributedStringForAttributionInfos:(NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos {
++ (NSAttributedString *)attributedStringForAttributionInfos:(NSArray<MGLAttributionInfo *> *)attributionInfos {
NSMutableArray *titles = [NSMutableArray arrayWithCapacity:attributionInfos.count];
for (MGLAttributionInfo *info in attributionInfos) {
NSMutableAttributedString *title = info.title.mutableCopy;
@@ -160,6 +165,7 @@
[NSURLQueryItem queryItemWithName:@"owner" value:stylePathComponents[1]],
[NSURLQueryItem queryItemWithName:@"id" value:stylePathComponents[2]],
[NSURLQueryItem queryItemWithName:@"access_token" value:[MGLAccountManager accessToken]],
+ [NSURLQueryItem queryItemWithName:@"map_sdk_version" value:[NSBundle mgl_frameworkInfoDictionary][@"MGLSemanticVersionString"]],
]];
}
}
@@ -253,7 +259,7 @@
}
}
-- (void)growArrayByAddingAttributionInfosFromArray:(NS_ARRAY_OF(MGLAttributionInfo *) *)infos {
+- (void)growArrayByAddingAttributionInfosFromArray:(NSArray<MGLAttributionInfo *> *)infos {
for (MGLAttributionInfo *info in infos) {
[self growArrayByAddingAttributionInfo:info];
}
diff --git a/platform/darwin/src/MGLAttributionInfo_Private.h b/platform/darwin/src/MGLAttributionInfo_Private.h
index c639752ac3..85c9ed796f 100644
--- a/platform/darwin/src/MGLAttributionInfo_Private.h
+++ b/platform/darwin/src/MGLAttributionInfo_Private.h
@@ -16,9 +16,9 @@ NS_ASSUME_NONNULL_BEGIN
@param fontSize The default text size in points.
@param linkColor The default link color.
*/
-+ (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosFromHTMLString:(nullable NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
++ (NSArray<MGLAttributionInfo *> *)attributionInfosFromHTMLString:(nullable NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
-+ (NSAttributedString *)attributedStringForAttributionInfos:(NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos;
++ (NSAttributedString *)attributedStringForAttributionInfos:(NSArray<MGLAttributionInfo *> *)attributionInfos;
/**
Returns a copy of the `URL` property modified to account for the given style
@@ -58,7 +58,7 @@ NS_ASSUME_NONNULL_BEGIN
@param infos An array of info objects to add to the receiver.
*/
-- (void)growArrayByAddingAttributionInfosFromArray:(NS_ARRAY_OF(MGLAttributionInfo *) *)infos;
+- (void)growArrayByAddingAttributionInfosFromArray:(NSArray<MGLAttributionInfo *> *)infos;
@end
diff --git a/platform/darwin/src/MGLBackgroundStyleLayer.h b/platform/darwin/src/MGLBackgroundStyleLayer.h
index 659903914c..d5c3ed5403 100644
--- a/platform/darwin/src/MGLBackgroundStyleLayer.h
+++ b/platform/darwin/src/MGLBackgroundStyleLayer.h
@@ -2,7 +2,6 @@
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLFoundation.h"
-#import "MGLStyleValue.h"
#import "MGLStyleLayer.h"
NS_ASSUME_NONNULL_BEGIN
@@ -42,40 +41,48 @@ which it is added.
/**
The color with which the background will be drawn.
- The default value of this property is an `MGLStyleValue` object containing
+ The default value of this property is an expression that evaluates to
`UIColor.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 instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ * Constant `UIColor` 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) MGLStyleValue<UIColor *> *backgroundColor;
+@property (nonatomic, null_resettable) NSExpression *backgroundColor;
#else
/**
The color with which the background will be drawn.
- The default value of this property is an `MGLStyleValue` object containing
+ 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 instance of:
+ 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *backgroundColor;
+@property (nonatomic, null_resettable) NSExpression *backgroundColor;
#endif
/**
@@ -88,18 +95,21 @@ which it is added.
/**
The opacity at which the background will be drawn.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `1`. Set this property to `nil` to reset
- it to the default value.
+ 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.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ * Constant numeric values between 0 and 1 inclusive
+ * 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) MGLStyleValue<NSNumber *> *backgroundOpacity;
+@property (nonatomic, null_resettable) NSExpression *backgroundOpacity;
/**
The transition affecting any changes to this layer’s `backgroundOpacity` property.
@@ -113,13 +123,19 @@ which it is added.
seamless patterns, image width and height must be a factor of two (2, 4, 8,
..., 512).
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant string values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *backgroundPattern;
+@property (nonatomic, null_resettable) NSExpression *backgroundPattern;
/**
The transition affecting any changes to this layer’s `backgroundPattern` property.
diff --git a/platform/darwin/src/MGLBackgroundStyleLayer.mm b/platform/darwin/src/MGLBackgroundStyleLayer.mm
index 47b491fc65..993645d3a8 100644
--- a/platform/darwin/src/MGLBackgroundStyleLayer.mm
+++ b/platform/darwin/src/MGLBackgroundStyleLayer.mm
@@ -32,21 +32,21 @@
#pragma mark - Accessing the Paint Attributes
-- (void)setBackgroundColor:(MGLStyleValue<MGLColor *> *)backgroundColor {
+- (void)setBackgroundColor:(NSExpression *)backgroundColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toInterpolatablePropertyValue(backgroundColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::PropertyValue<mbgl::Color>>(backgroundColor);
self.rawLayer->setBackgroundColor(mbglValue);
}
-- (MGLStyleValue<MGLColor *> *)backgroundColor {
+- (NSExpression *)backgroundColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getBackgroundColor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(self.rawLayer->getDefaultBackgroundColor());
+ propertyValue = self.rawLayer->getDefaultBackgroundColor();
}
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(propertyValue);
}
- (void)setBackgroundColorTransition:(MGLTransition )transition {
@@ -67,21 +67,21 @@
return transition;
}
-- (void)setBackgroundOpacity:(MGLStyleValue<NSNumber *> *)backgroundOpacity {
+- (void)setBackgroundOpacity:(NSExpression *)backgroundOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(backgroundOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(backgroundOpacity);
self.rawLayer->setBackgroundOpacity(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)backgroundOpacity {
+- (NSExpression *)backgroundOpacity {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getBackgroundOpacity();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultBackgroundOpacity());
+ propertyValue = self.rawLayer->getDefaultBackgroundOpacity();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setBackgroundOpacityTransition:(MGLTransition )transition {
@@ -102,21 +102,22 @@
return transition;
}
-- (void)setBackgroundPattern:(MGLStyleValue<NSString *> *)backgroundPattern {
+- (void)setBackgroundPattern:(NSExpression *)backgroundPattern {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(backgroundPattern);
+ auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue<mbgl::style::PropertyValue<std::string>>(backgroundPattern);
self.rawLayer->setBackgroundPattern(mbglValue);
}
-- (MGLStyleValue<NSString *> *)backgroundPattern {
+- (NSExpression *)backgroundPattern {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getBackgroundPattern();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(self.rawLayer->getDefaultBackgroundPattern());
+ propertyValue = self.rawLayer->getDefaultBackgroundPattern();
}
- return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(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 ea95f6beef..06b4de32f0 100644
--- a/platform/darwin/src/MGLCircleStyleLayer.h
+++ b/platform/darwin/src/MGLCircleStyleLayer.h
@@ -2,7 +2,6 @@
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLFoundation.h"
-#import "MGLStyleValue.h"
#import "MGLVectorStyleLayer.h"
NS_ASSUME_NONNULL_BEGIN
@@ -42,7 +41,7 @@ typedef NS_ENUM(NSUInteger, MGLCircleScaleAlignment) {
};
/**
- Controls the translation reference point.
+ Controls the frame of reference for `MGLCircleStyleLayer.circleTranslation`.
Values of this type are used in the `MGLCircleStyleLayer.circleTranslationAnchor`
property.
@@ -63,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,12 +83,11 @@ typedef NS_ENUM(NSUInteger, MGLCircleTranslationAnchor) {
```swift
let layer = MGLCircleStyleLayer(identifier: "circles", source: population)
layer.sourceLayerIdentifier = "population"
- layer.circleColor = MGLStyleValue(rawValue: .green)
- layer.circleRadius = MGLStyleValue(interpolationMode: .exponential,
- cameraStops: [12: MGLStyleValue(rawValue: 2),
- 22: MGLStyleValue(rawValue: 180)],
- options: [.interpolationBase: 1.75])
- layer.circleOpacity = MGLStyleValue(rawValue: 0.7)
+ layer.circleColor = NSExpression(forConstantValue: UIColor.green)
+ layer.circleRadius = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'exponential', 1.75, %@)",
+ [12: 2,
+ 22: 180])
+ layer.circleOpacity = NSExpression(forConstantValue: 0.7)
layer.predicate = NSPredicate(format: "%K == %@", "marital-status", "married")
mapView.style?.addLayer(layer)
```
@@ -117,27 +116,19 @@ MGL_EXPORT
Amount to blur the circle. 1 blurs the circle such that only the centerpoint is
full opacity.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
-
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric 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) MGLStyleValue<NSNumber *> *circleBlur;
+@property (nonatomic, null_resettable) NSExpression *circleBlur;
/**
The transition affecting any changes to this layer’s `circleBlur` property.
@@ -150,52 +141,38 @@ MGL_EXPORT
/**
The fill color of the circle.
- The default value of this property is an `MGLStyleValue` object containing
+ The default value of this property is an expression that evaluates to
`UIColor.blackColor`. Set this property to `nil` to reset it to the default
value.
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ You can set this property to an expression containing any of the following:
+
+ * Constant `UIColor` 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) MGLStyleValue<UIColor *> *circleColor;
+@property (nonatomic, null_resettable) NSExpression *circleColor;
#else
/**
The fill color of the circle.
- The default value of this property is an `MGLStyleValue` object containing
+ 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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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) MGLStyleValue<NSColor *> *circleColor;
+@property (nonatomic, null_resettable) NSExpression *circleColor;
#endif
/**
@@ -208,27 +185,19 @@ MGL_EXPORT
/**
The opacity at which the circle will be drawn.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `1`. Set this property to `nil` to reset
- it to the default value.
-
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values between 0 and 1 inclusive
+ * 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) MGLStyleValue<NSNumber *> *circleOpacity;
+@property (nonatomic, null_resettable) NSExpression *circleOpacity;
/**
The transition affecting any changes to this layer’s `circleOpacity` property.
@@ -240,44 +209,44 @@ MGL_EXPORT
/**
Orientation of circle when map is pitched.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLCirclePitchAlignmentViewport`. Set this
- property to `nil` to reset it to the default value.
+ The default value of this property is an expression that evaluates to
+ `viewport`. 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:
- You can set this property to an instance of:
+ * Constant `MGLCirclePitchAlignment` values
+ * Any of the following constant string values:
+ * `map`: The circle is aligned to the plane of the map.
+ * `viewport`: The circle is aligned to the plane of the viewport.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circlePitchAlignment;
+@property (nonatomic, null_resettable) NSExpression *circlePitchAlignment;
/**
Circle radius.
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `5`. Set this property to `nil` to reset
- it to the default value.
-
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values no less than 0
+ * 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) MGLStyleValue<NSNumber *> *circleRadius;
+@property (nonatomic, null_resettable) NSExpression *circleRadius;
/**
The transition affecting any changes to this layer’s `circleRadius` property.
@@ -289,74 +258,69 @@ MGL_EXPORT
/**
Controls the scaling behavior of the circle when the map is pitched.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLCircleScaleAlignmentMap`. Set this property to
- `nil` to reset it to the default value.
+ The default value of this property is an expression that evaluates to `map`.
+ 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-circle-pitch-scale"><code>circle-pitch-scale</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ You can set this property to an expression containing any of the following:
+
+ * Constant `MGLCircleScaleAlignment` values
+ * Any of the following constant string values:
+ * `map`: Circles are scaled according to their apparent distance to the
+ camera.
+ * `viewport`: Circles are not scaled.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
+
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleScaleAlignment;
+@property (nonatomic, null_resettable) NSExpression *circleScaleAlignment;
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circlePitchScale __attribute__((unavailable("Use circleScaleAlignment instead.")));
+@property (nonatomic, null_resettable) NSExpression *circlePitchScale __attribute__((unavailable("Use circleScaleAlignment instead.")));
#if TARGET_OS_IPHONE
/**
The stroke color of the circle.
- The default value of this property is an `MGLStyleValue` object containing
+ The default value of this property is an expression that evaluates to
`UIColor.blackColor`. Set this property to `nil` to reset it to the default
value.
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ You can set this property to an expression containing any of the following:
+
+ * Constant `UIColor` 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) MGLStyleValue<UIColor *> *circleStrokeColor;
+@property (nonatomic, null_resettable) NSExpression *circleStrokeColor;
#else
/**
The stroke color of the circle.
- The default value of this property is an `MGLStyleValue` object containing
+ 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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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) MGLStyleValue<NSColor *> *circleStrokeColor;
+@property (nonatomic, null_resettable) NSExpression *circleStrokeColor;
#endif
/**
@@ -369,27 +333,19 @@ MGL_EXPORT
/**
The opacity of the circle's stroke.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `1`. Set this property to `nil` to reset
- it to the default value.
-
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values between 0 and 1 inclusive
+ * 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) MGLStyleValue<NSNumber *> *circleStrokeOpacity;
+@property (nonatomic, null_resettable) NSExpression *circleStrokeOpacity;
/**
The transition affecting any changes to this layer’s `circleStrokeOpacity` property.
@@ -404,27 +360,19 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
-
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values no less than 0
+ * 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) MGLStyleValue<NSNumber *> *circleStrokeWidth;
+@property (nonatomic, null_resettable) NSExpression *circleStrokeWidth;
/**
The transition affecting any changes to this layer’s `circleStrokeWidth` property.
@@ -439,7 +387,7 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points downward. Set this property to `nil` to reset it to the default value.
@@ -447,21 +395,25 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-circle-translate"><code>circle-translate</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant `CGVector` 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslation;
+@property (nonatomic, null_resettable) NSExpression *circleTranslation;
#else
/**
The geometry's offset.
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points upward. Set this property to `nil` to reset it to the default value.
@@ -469,14 +421,18 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-circle-translate"><code>circle-translate</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ * Constant `CGVector` 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) MGLStyleValue<NSValue *> *circleTranslation;
+@property (nonatomic, null_resettable) NSExpression *circleTranslation;
#endif
/**
@@ -486,14 +442,13 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition circleTranslationTransition;
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslate __attribute__((unavailable("Use circleTranslation instead.")));
+@property (nonatomic, null_resettable) NSExpression *circleTranslate __attribute__((unavailable("Use circleTranslation instead.")));
/**
- Controls the translation reference point.
+ Controls the frame of reference for `circleTranslation`.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLCircleTranslationAnchorMap`. Set this property
- to `nil` to reset it to the default value.
+ The default value of this property is an expression that evaluates to `map`.
+ Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `circleTranslation` is non-`nil`.
Otherwise, it is ignored.
@@ -502,15 +457,24 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-circle-translate-anchor"><code>circle-translate-anchor</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant `MGLCircleTranslationAnchor` values
+ * Any of the following constant string values:
+ * `map`: The circle is translated relative to the map.
+ * `viewport`: The circle is translated relative to the viewport.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslationAnchor;
+@property (nonatomic, null_resettable) NSExpression *circleTranslationAnchor;
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslateAnchor __attribute__((unavailable("Use circleTranslationAnchor instead.")));
+@property (nonatomic, null_resettable) NSExpression *circleTranslateAnchor __attribute__((unavailable("Use circleTranslationAnchor instead.")));
@end
diff --git a/platform/darwin/src/MGLCircleStyleLayer.mm b/platform/darwin/src/MGLCircleStyleLayer.mm
index 71ae37035e..0be3920987 100644
--- a/platform/darwin/src/MGLCircleStyleLayer.mm
+++ b/platform/darwin/src/MGLCircleStyleLayer.mm
@@ -87,21 +87,21 @@ namespace mbgl {
#pragma mark - Accessing the Paint Attributes
-- (void)setCircleBlur:(MGLStyleValue<NSNumber *> *)circleBlur {
+- (void)setCircleBlur:(NSExpression *)circleBlur {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(circleBlur);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(circleBlur);
self.rawLayer->setCircleBlur(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)circleBlur {
+- (NSExpression *)circleBlur {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCircleBlur();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleBlur());
+ propertyValue = self.rawLayer->getDefaultCircleBlur();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setCircleBlurTransition:(MGLTransition )transition {
@@ -122,21 +122,21 @@ namespace mbgl {
return transition;
}
-- (void)setCircleColor:(MGLStyleValue<MGLColor *> *)circleColor {
+- (void)setCircleColor:(NSExpression *)circleColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(circleColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<mbgl::Color>>(circleColor);
self.rawLayer->setCircleColor(mbglValue);
}
-- (MGLStyleValue<MGLColor *> *)circleColor {
+- (NSExpression *)circleColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCircleColor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleColor());
+ propertyValue = self.rawLayer->getDefaultCircleColor();
}
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(propertyValue);
}
- (void)setCircleColorTransition:(MGLTransition )transition {
@@ -157,21 +157,21 @@ namespace mbgl {
return transition;
}
-- (void)setCircleOpacity:(MGLStyleValue<NSNumber *> *)circleOpacity {
+- (void)setCircleOpacity:(NSExpression *)circleOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(circleOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(circleOpacity);
self.rawLayer->setCircleOpacity(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)circleOpacity {
+- (NSExpression *)circleOpacity {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCircleOpacity();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleOpacity());
+ propertyValue = self.rawLayer->getDefaultCircleOpacity();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setCircleOpacityTransition:(MGLTransition )transition {
@@ -192,38 +192,38 @@ namespace mbgl {
return transition;
}
-- (void)setCirclePitchAlignment:(MGLStyleValue<NSValue *> *)circlePitchAlignment {
+- (void)setCirclePitchAlignment:(NSExpression *)circlePitchAlignment {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLCirclePitchAlignment>().toEnumPropertyValue(circlePitchAlignment);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLCirclePitchAlignment>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::AlignmentType>>(circlePitchAlignment);
self.rawLayer->setCirclePitchAlignment(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)circlePitchAlignment {
+- (NSExpression *)circlePitchAlignment {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCirclePitchAlignment();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLCirclePitchAlignment>().toEnumStyleValue(self.rawLayer->getDefaultCirclePitchAlignment());
+ propertyValue = self.rawLayer->getDefaultCirclePitchAlignment();
}
- return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLCirclePitchAlignment>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLCirclePitchAlignment>().toExpression(propertyValue);
}
-- (void)setCircleRadius:(MGLStyleValue<NSNumber *> *)circleRadius {
+- (void)setCircleRadius:(NSExpression *)circleRadius {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(circleRadius);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(circleRadius);
self.rawLayer->setCircleRadius(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)circleRadius {
+- (NSExpression *)circleRadius {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCircleRadius();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleRadius());
+ propertyValue = self.rawLayer->getDefaultCircleRadius();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setCircleRadiusTransition:(MGLTransition )transition {
@@ -244,45 +244,45 @@ namespace mbgl {
return transition;
}
-- (void)setCircleScaleAlignment:(MGLStyleValue<NSValue *> *)circleScaleAlignment {
+- (void)setCircleScaleAlignment:(NSExpression *)circleScaleAlignment {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCircleScaleAlignment>().toEnumPropertyValue(circleScaleAlignment);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCircleScaleAlignment>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::CirclePitchScaleType>>(circleScaleAlignment);
self.rawLayer->setCirclePitchScale(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)circleScaleAlignment {
+- (NSExpression *)circleScaleAlignment {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCirclePitchScale();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCircleScaleAlignment>().toEnumStyleValue(self.rawLayer->getDefaultCirclePitchScale());
+ propertyValue = self.rawLayer->getDefaultCirclePitchScale();
}
- return MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCircleScaleAlignment>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCircleScaleAlignment>().toExpression(propertyValue);
}
-- (void)setCirclePitchScale:(MGLStyleValue<NSValue *> *)circlePitchScale {
+- (void)setCirclePitchScale:(NSExpression *)circlePitchScale {
}
-- (MGLStyleValue<NSValue *> *)circlePitchScale {
+- (NSExpression *)circlePitchScale {
return self.circleScaleAlignment;
}
-- (void)setCircleStrokeColor:(MGLStyleValue<MGLColor *> *)circleStrokeColor {
+- (void)setCircleStrokeColor:(NSExpression *)circleStrokeColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(circleStrokeColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<mbgl::Color>>(circleStrokeColor);
self.rawLayer->setCircleStrokeColor(mbglValue);
}
-- (MGLStyleValue<MGLColor *> *)circleStrokeColor {
+- (NSExpression *)circleStrokeColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCircleStrokeColor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleStrokeColor());
+ propertyValue = self.rawLayer->getDefaultCircleStrokeColor();
}
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(propertyValue);
}
- (void)setCircleStrokeColorTransition:(MGLTransition )transition {
@@ -303,21 +303,21 @@ namespace mbgl {
return transition;
}
-- (void)setCircleStrokeOpacity:(MGLStyleValue<NSNumber *> *)circleStrokeOpacity {
+- (void)setCircleStrokeOpacity:(NSExpression *)circleStrokeOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(circleStrokeOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(circleStrokeOpacity);
self.rawLayer->setCircleStrokeOpacity(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)circleStrokeOpacity {
+- (NSExpression *)circleStrokeOpacity {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCircleStrokeOpacity();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleStrokeOpacity());
+ propertyValue = self.rawLayer->getDefaultCircleStrokeOpacity();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setCircleStrokeOpacityTransition:(MGLTransition )transition {
@@ -338,21 +338,21 @@ namespace mbgl {
return transition;
}
-- (void)setCircleStrokeWidth:(MGLStyleValue<NSNumber *> *)circleStrokeWidth {
+- (void)setCircleStrokeWidth:(NSExpression *)circleStrokeWidth {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(circleStrokeWidth);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(circleStrokeWidth);
self.rawLayer->setCircleStrokeWidth(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)circleStrokeWidth {
+- (NSExpression *)circleStrokeWidth {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCircleStrokeWidth();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleStrokeWidth());
+ propertyValue = self.rawLayer->getDefaultCircleStrokeWidth();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setCircleStrokeWidthTransition:(MGLTransition )transition {
@@ -373,21 +373,21 @@ namespace mbgl {
return transition;
}
-- (void)setCircleTranslation:(MGLStyleValue<NSValue *> *)circleTranslation {
+- (void)setCircleTranslation:(NSExpression *)circleTranslation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toInterpolatablePropertyValue(circleTranslation);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue<mbgl::style::PropertyValue<std::array<float, 2>>>(circleTranslation);
self.rawLayer->setCircleTranslate(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)circleTranslation {
+- (NSExpression *)circleTranslation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCircleTranslate();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(self.rawLayer->getDefaultCircleTranslate());
+ propertyValue = self.rawLayer->getDefaultCircleTranslate();
}
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toExpression(propertyValue);
}
- (void)setCircleTranslationTransition:(MGLTransition )transition {
@@ -408,34 +408,34 @@ namespace mbgl {
return transition;
}
-- (void)setCircleTranslate:(MGLStyleValue<NSValue *> *)circleTranslate {
+- (void)setCircleTranslate:(NSExpression *)circleTranslate {
}
-- (MGLStyleValue<NSValue *> *)circleTranslate {
+- (NSExpression *)circleTranslate {
return self.circleTranslation;
}
-- (void)setCircleTranslationAnchor:(MGLStyleValue<NSValue *> *)circleTranslationAnchor {
+- (void)setCircleTranslationAnchor:(NSExpression *)circleTranslationAnchor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslationAnchor>().toEnumPropertyValue(circleTranslationAnchor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslationAnchor>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType>>(circleTranslationAnchor);
self.rawLayer->setCircleTranslateAnchor(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)circleTranslationAnchor {
+- (NSExpression *)circleTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getCircleTranslateAnchor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslationAnchor>().toEnumStyleValue(self.rawLayer->getDefaultCircleTranslateAnchor());
+ propertyValue = self.rawLayer->getDefaultCircleTranslateAnchor();
}
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslationAnchor>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslationAnchor>().toExpression(propertyValue);
}
-- (void)setCircleTranslateAnchor:(MGLStyleValue<NSValue *> *)circleTranslateAnchor {
+- (void)setCircleTranslateAnchor:(NSExpression *)circleTranslateAnchor {
}
-- (MGLStyleValue<NSValue *> *)circleTranslateAnchor {
+- (NSExpression *)circleTranslateAnchor {
return self.circleTranslationAnchor;
}
diff --git a/platform/darwin/src/MGLCompassDirectionFormatter.m b/platform/darwin/src/MGLCompassDirectionFormatter.m
index 5f0cfae6f7..1ac6a82162 100644
--- a/platform/darwin/src/MGLCompassDirectionFormatter.m
+++ b/platform/darwin/src/MGLCompassDirectionFormatter.m
@@ -15,8 +15,8 @@
}
- (NSString *)stringFromDirection:(CLLocationDirection)direction {
- static NS_ARRAY_OF(NSString *) *shortStrings;
- static NS_ARRAY_OF(NSString *) *longStrings;
+ static NSArray<NSString *> *shortStrings;
+ static NSArray<NSString *> *longStrings;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shortStrings = @[
diff --git a/platform/darwin/src/MGLComputedShapeSource.h b/platform/darwin/src/MGLComputedShapeSource.h
new file mode 100644
index 0000000000..7e0037df89
--- /dev/null
+++ b/platform/darwin/src/MGLComputedShapeSource.h
@@ -0,0 +1,165 @@
+#import "MGLFoundation.h"
+#import "MGLGeometry.h"
+#import "MGLTypes.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
+ called on main thread, they will be called on the caller's `requestQueue`.
+ */
+@protocol MGLComputedShapeSourceDataSource <NSObject>
+
+@optional
+/**
+ Fetch features for a tile. This method will not be invoked on the main queue, it
+ will be invoked on the caller's `requestQueue`.
+ @param x Tile X coordinate.
+ @param y Tile Y coordinate.
+ @param zoomLevel Tile zoom level.
+ */
+- (NSArray<MGLShape <MGLFeature> *>*)featuresInTileAtX:(NSUInteger)x y:(NSUInteger)y zoomLevel:(NSUInteger)zoomLevel;
+
+/**
+ Fetch features for a tile. This method will not be invoked on the main queue, it
+ will be invoked on the caller's `requestQueue`.
+ @param bounds The bounds to fetch data for.
+ @param zoomLevel Tile zoom level.
+ */
+- (NSArray<MGLShape <MGLFeature> *>*)featuresInCoordinateBounds:(MGLCoordinateBounds)bounds zoomLevel:(NSUInteger)zoomLevel;
+
+@end
+
+/**
+ `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.
+
+ `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 : 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.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options NS_DESIGNATED_INITIALIZER;
+
+/**
+ Returns a custom shape data source initialized with an identifier, data source, 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.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier dataSource:(id<MGLComputedShapeSourceDataSource>)dataSource options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options;
+
+/**
+ Invalidates all the features and properties intersecting with or contained in
+ the specified bounds. New fetch requests will immediately be invoked on the
+ `MGLComputedShapeSourceDataSource`.
+ @param bounds Coordinate bounds to invalidate.
+ */
+- (void) invalidateBounds:(MGLCoordinateBounds)bounds;
+
+/**
+ Invalidates all the feautres and properties of a given tile. A new fetch request
+ will immediately be invoked on the `MGLComputedShapeSourceDataSource`.
+ @param x Tile X coordinate.
+ @param y Tile Y coordinate.
+ @param zoomLevel Tile zoom level.
+ */
+- (void) invalidateTileAtX:(NSUInteger)x y:(NSUInteger)y zoomLevel:(NSUInteger)zoomLevel;
+
+/**
+ Set a new set of features for a tile. This method can be invkoed from background threads.
+ For best performance, use this method only to update tiles that have already been requested
+ through `MGLComputedShapeSourceDataSource.`
+ @param features Features for the tile.
+ @param x Tile X coordinate.
+ @param y Tile Y coordinate.
+ @param zoomLevel Tile zoom level.
+ */
+- (void) setFeatures:(NSArray<MGLShape <MGLFeature> *>*)features inTileAtX:(NSUInteger)x y:(NSUInteger)y zoomLevel:(NSUInteger)zoomLevel;
+
+/**
+ An object that implements the `MGLComputedShapeSourceDataSource` protocol that will be queried for tile data.
+ */
+@property (nonatomic, weak, nullable) id<MGLComputedShapeSourceDataSource> dataSource;
+
+/**
+ A queue that calls to the data source will be made on.
+ */
+@property (nonatomic, readonly) NSOperationQueue *requestQueue;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLComputedShapeSource.mm b/platform/darwin/src/MGLComputedShapeSource.mm
new file mode 100644
index 0000000000..04734d0ef5
--- /dev/null
+++ b/platform/darwin/src/MGLComputedShapeSource.mm
@@ -0,0 +1,225 @@
+#import "MGLComputedShapeSource_Private.h"
+
+#import "MGLMapView_Private.h"
+#import "MGLSource_Private.h"
+#import "MGLShape_Private.h"
+#import "MGLGeometry_Private.h"
+
+#include <mbgl/map/map.hpp>
+#include <mbgl/style/sources/custom_geometry_source.hpp>
+#include <mbgl/tile/tile_id.hpp>
+#include <mbgl/util/geojson.hpp>
+
+const MGLShapeSourceOption MGLShapeSourceOptionWrapsCoordinates = @"MGLShapeSourceOptionWrapsCoordinates";
+const MGLShapeSourceOption MGLShapeSourceOptionClipsCoordinates = @"MGLShapeSourceOptionClipsCoordinates";
+
+mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDictionary(NSDictionary<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;
+}
+
+@property (nonatomic, readwrite) NSDictionary *options;
+@property (nonatomic, assign) BOOL dataSourceImplementsFeaturesForTile;
+@property (nonatomic, assign) BOOL dataSourceImplementsFeaturesForBounds;
+
+@end
+
+@interface MGLComputedShapeSourceFetchOperation : NSOperation
+
+@property (nonatomic, readonly) uint8_t z;
+@property (nonatomic, readonly) uint32_t x;
+@property (nonatomic, readonly) uint32_t y;
+@property (nonatomic, assign) BOOL dataSourceImplementsFeaturesForTile;
+@property (nonatomic, assign) BOOL dataSourceImplementsFeaturesForBounds;
+@property (nonatomic, weak, nullable) id<MGLComputedShapeSourceDataSource> dataSource;
+@property (nonatomic, nullable) mbgl::style::CustomGeometrySource *rawSource;
+
+- (instancetype)initForSource:(MGLComputedShapeSource*)source tile:(const mbgl::CanonicalTileID&)tileId;
+
+@end
+
+@implementation MGLComputedShapeSourceFetchOperation
+
+- (instancetype)initForSource:(MGLComputedShapeSource*)source tile:(const mbgl::CanonicalTileID&)tileID {
+ self = [super init];
+ _z = tileID.z;
+ _x = tileID.x;
+ _y = tileID.y;
+ _dataSourceImplementsFeaturesForTile = source.dataSourceImplementsFeaturesForTile;
+ _dataSourceImplementsFeaturesForBounds = source.dataSourceImplementsFeaturesForBounds;
+ _dataSource = source.dataSource;
+ mbgl::style::CustomGeometrySource *rawSource = static_cast<mbgl::style::CustomGeometrySource *>(source.rawSource);
+ _rawSource = rawSource;
+ return self;
+}
+
+- (void)main {
+ if ([self isCancelled]) {
+ return;
+ }
+
+ NSArray<MGLShape <MGLFeature> *> *data;
+ if(!self.dataSource) {
+ data = nil;
+ } else if(self.dataSourceImplementsFeaturesForTile) {
+ data = [self.dataSource featuresInTileAtX:self.x
+ y:self.y
+ zoomLevel:self.z];
+ } else {
+ mbgl::CanonicalTileID tileID = mbgl::CanonicalTileID(self.z, self.x, self.y);
+ mbgl::LatLngBounds tileBounds = mbgl::LatLngBounds(tileID);
+ data = [self.dataSource featuresInCoordinateBounds:MGLCoordinateBoundsFromLatLngBounds(tileBounds)
+ zoomLevel:self.z];
+ }
+
+ if(![self isCancelled]) {
+ mbgl::FeatureCollection featureCollection;
+ featureCollection.reserve(data.count);
+ for (MGLShape <MGLFeature> * feature in data) {
+ mbgl::Feature geoJsonObject = [feature geoJSONObject].get<mbgl::Feature>();
+ featureCollection.push_back(geoJsonObject);
+ }
+ const auto geojson = mbgl::GeoJSON{featureCollection};
+ if(![self isCancelled] && self.rawSource) {
+ self.rawSource->setTileData(mbgl::CanonicalTileID(self.z, self.x, self.y), geojson);
+ }
+ }
+}
+
+- (void)cancel {
+ [super cancel];
+ self.rawSource = NULL;
+}
+
+@end
+
+@implementation MGLComputedShapeSource
+
+- (instancetype)initWithIdentifier:(NSString *)identifier options:(NSDictionary<MGLShapeSourceOption, id> *)options {
+ NSOperationQueue *requestQueue = [[NSOperationQueue alloc] init];
+ requestQueue.name = [NSString stringWithFormat:@"mgl.MGLComputedShapeSource.%@", identifier];
+ requestQueue.qualityOfService = NSQualityOfServiceUtility;
+ requestQueue.maxConcurrentOperationCount = 4;
+
+ auto sourceOptions = MBGLCustomGeometrySourceOptionsFromDictionary(options);
+ sourceOptions.fetchTileFunction = ^void(const mbgl::CanonicalTileID& tileID) {
+ NSOperation *operation = [[MGLComputedShapeSourceFetchOperation alloc] initForSource:self tile:tileID];
+ [requestQueue addOperation:operation];
+ };
+
+ sourceOptions.cancelTileFunction = ^void(const mbgl::CanonicalTileID& tileID) {
+ for (MGLComputedShapeSourceFetchOperation *operation in requestQueue.operations) {
+ if (operation.x == tileID.x && operation.y == tileID.y && operation.z == tileID.z) {
+ [operation cancel];
+ }
+ }
+ };
+
+ auto source = std::make_unique<mbgl::style::CustomGeometrySource>(identifier.UTF8String, sourceOptions);
+
+ if (self = [super initWithPendingSource:std::move(source)]) {
+ _requestQueue = requestQueue;
+ }
+ return self;
+}
+
+- (instancetype)initWithIdentifier:(NSString *)identifier dataSource:(id<MGLComputedShapeSourceDataSource>)dataSource options:(NSDictionary<MGLShapeSourceOption, id> *)options {
+ if (self = [self initWithIdentifier:identifier options:options]) {
+ [self setDataSource:dataSource];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [self.requestQueue cancelAllOperations];
+}
+
+- (void)setFeatures:(NSArray<MGLShape <MGLFeature> *>*)features inTileAtX:(NSUInteger)x y:(NSUInteger)y zoomLevel:(NSUInteger)zoomLevel {
+ mbgl::CanonicalTileID tileID = mbgl::CanonicalTileID((uint8_t)zoomLevel, (uint32_t)x, (uint32_t)y);
+ mbgl::FeatureCollection featureCollection;
+ featureCollection.reserve(features.count);
+ for (MGLShape <MGLFeature> * feature in features) {
+ mbgl::Feature geoJsonObject = [feature geoJSONObject].get<mbgl::Feature>();
+ featureCollection.push_back(geoJsonObject);
+ }
+ const auto geojson = mbgl::GeoJSON{featureCollection};
+ static_cast<mbgl::style::CustomGeometrySource *>(self.rawSource)->setTileData(tileID, geojson);
+}
+
+- (void)setDataSource:(id<MGLComputedShapeSourceDataSource>)dataSource {
+ [self.requestQueue cancelAllOperations];
+ // Check which method the datasource implements, to avoid having to check for each tile
+ self.dataSourceImplementsFeaturesForTile = [dataSource respondsToSelector:@selector(featuresInTileAtX:y:zoomLevel:)];
+ self.dataSourceImplementsFeaturesForBounds = [dataSource respondsToSelector:@selector(featuresInCoordinateBounds:zoomLevel:)];
+
+ if(!self.dataSourceImplementsFeaturesForBounds && !self.dataSourceImplementsFeaturesForTile) {
+ [NSException raise:@"Invalid Datasource" format:@"Datasource does not implement any MGLComputedShapeSourceDataSource methods"];
+ } else if(self.dataSourceImplementsFeaturesForBounds && self.dataSourceImplementsFeaturesForTile) {
+ [NSException raise:@"Invalid Datasource" format:@"Datasource implements multiple MGLComputedShapeSourceDataSource methods"];
+ }
+
+ _dataSource = dataSource;
+}
+
+- (void) invalidateBounds:(MGLCoordinateBounds)bounds {
+ ((mbgl::style::CustomGeometrySource *)self.rawSource)->invalidateRegion(MGLLatLngBoundsFromCoordinateBounds(bounds));
+}
+
+- (void) invalidateTileAtX:(NSUInteger)x y:(NSUInteger)y zoomLevel:(NSUInteger)z {
+ ((mbgl::style::CustomGeometrySource *)self.rawSource)->invalidateTile(mbgl::CanonicalTileID(z, (unsigned int)x, (unsigned int)y));
+}
+
+@end
diff --git a/platform/darwin/src/MGLComputedShapeSource_Private.h b/platform/darwin/src/MGLComputedShapeSource_Private.h
new file mode 100644
index 0000000000..ec075e4bd7
--- /dev/null
+++ b/platform/darwin/src/MGLComputedShapeSource_Private.h
@@ -0,0 +1,12 @@
+#import "MGLFoundation.h"
+#import "MGLTypes.h"
+#import "MGLComputedShapeSource.h"
+
+#include <mbgl/style/sources/custom_geometry_source.hpp>
+
+NS_ASSUME_NONNULL_BEGIN
+
+MGL_EXPORT
+mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDictionary(NSDictionary<MGLShapeSourceOption, id> *options);
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLConversion.h b/platform/darwin/src/MGLConversion.h
index d6363b28eb..92a6720e6a 100644
--- a/platform/darwin/src/MGLConversion.h
+++ b/platform/darwin/src/MGLConversion.h
@@ -1,9 +1,4 @@
-#import <Foundation/Foundation.h>
-
-#include <mbgl/util/logging.hpp>
#include <mbgl/style/conversion.hpp>
-#include <mbgl/util/feature.hpp>
-#include <mbgl/util/optional.hpp>
NS_ASSUME_NONNULL_BEGIN
@@ -11,128 +6,151 @@ namespace mbgl {
namespace style {
namespace conversion {
-/**
- A minimal wrapper class conforming to the requirements for `objectMember(v, name)` (see mbgl/style/conversion.hpp)
- This is necessary because using `NSObject*` as the value type in `optional<NSObject*>` causes problems for the ARC,
- due to things like `optional(const value_type& __v)`
- */
-class OptionalNSObjectValue {
+// A wrapper class for `id`, so as not to confuse ARC.
+class Holder {
public:
- OptionalNSObjectValue(NSObject * _Nullable _value) : value(_value) {}
-
- explicit operator bool() const {
- return value;
+ Holder(const id v) : value(v) {}
+ const id value;
+};
+
+template <>
+class ConversionTraits<Holder> {
+public:
+ static bool isUndefined(const Holder& holder) {
+ const id value = holder.value;
+ return !value || value == [NSNull null];
}
-
- NSObject * _Nullable operator*() {
- NSCAssert(this, @"Expected non-null value.");
- return value;
+
+ static bool isArray(const Holder& holder) {
+ const id value = holder.value;
+ return [value isKindOfClass:[NSArray class]];
}
-private:
- NSObject * _Nullable value;
-};
-inline bool isUndefined(const id value) {
- return !value || value == [NSNull null];
-}
+ static bool isObject(const Holder& holder) {
+ const id value = holder.value;
+ return [value isKindOfClass:[NSDictionary class]];
+ }
-inline bool isArray(const id value) {
- return [value isKindOfClass:[NSArray class]];
-}
+ static std::size_t arrayLength(const Holder& holder) {
+ const id value = holder.value;
+ NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for getLength().");
+ NSArray *array = value;
+ auto length = [array count];
+ NSCAssert(length <= std::numeric_limits<size_t>::max(), @"Array length out of bounds.");
+ return length;
+ }
-inline bool isObject(const id value) {
- return [value isKindOfClass:[NSDictionary class]];
-}
+ static Holder arrayMember(const Holder& holder, std::size_t i) {
+ const id value = holder.value;
+ NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for get(int).");
+ NSCAssert(i < NSUIntegerMax, @"Index must be less than NSUIntegerMax");
+ return {[value objectAtIndex: i]};
+ }
-inline std::size_t arrayLength(const id value) {
- NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for getLength().");
- NSArray *array = value;
- auto length = [array count];
- NSCAssert(length <= std::numeric_limits<size_t>::max(), @"Array length out of bounds.");
- return length;
-}
+ static optional<Holder> objectMember(const Holder& holder, const char *key) {
+ const id value = holder.value;
+ NSCAssert([value isKindOfClass:[NSDictionary class]], @"Value must be an NSDictionary for get(string).");
+ NSObject *member = [value objectForKey: @(key)];
+ if (member && member != [NSNull null]) {
+ return {member};
+ } else {
+ return {};
+ }
+ }
-inline NSObject *arrayMember(const id value, std::size_t i) {
- NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for get(int).");
- NSCAssert(i < NSUIntegerMax, @"Index must be less than NSUIntegerMax");
- return [value objectAtIndex: i];
-}
+// Compiler is wrong about `Fn` parameter missing a nullability specifier.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnullability-completeness"
+ template <class Fn>
+ static optional<Error> eachMember(const Holder& holder, Fn&& visit) {
+#pragma clang diagnostic pop
+ [holder.value enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
+ auto result = visit(std::string(static_cast<const char *>([key UTF8String])), obj);
+ if (result) {
+ *stop = YES;
+ }
+ }];
+ return {};
+ }
-inline OptionalNSObjectValue objectMember(const id value, const char *key) {
- NSCAssert([value isKindOfClass:[NSDictionary class]], @"Value must be an NSDictionary for get(string).");
- NSObject *member = [value objectForKey: @(key)];
- if (member && member != [NSNull null]) {
- return { member };
- } else {
- return { nullptr };
+ static optional<bool> toBool(const Holder& holder) {
+ const id value = holder.value;
+ if (_isBool(value)) {
+ return ((NSNumber *)value).boolValue;
+ } else {
+ return {};
+ }
}
-}
-// Not implemented (unneeded for MGLStyleFunction conversion):
-// optional<Error> eachMember(const NSObject*, Fn&&)
+ static optional<float> toNumber(const Holder& holder) {
+ const id value = holder.value;
+ if (_isNumber(value)) {
+ return ((NSNumber *)value).floatValue;
+ } else {
+ return {};
+ }
+ }
-inline bool _isBool(const id value) {
- if (![value isKindOfClass:[NSNumber class]]) return false;
- // char: 32-bit boolean
- // BOOL: 64-bit boolean
- NSNumber *number = value;
- return ((strcmp([number objCType], @encode(char)) == 0) ||
- (strcmp([number objCType], @encode(BOOL)) == 0));
-}
-
-inline bool _isNumber(const id value) {
- return [value isKindOfClass:[NSNumber class]] && !_isBool(value);
-}
-
-inline bool _isString(const id value) {
- return [value isKindOfClass:[NSString class]];
-}
+ static optional<double> toDouble(const Holder& holder) {
+ const id value = holder.value;
+ if (_isNumber(value)) {
+ return ((NSNumber *)value).doubleValue;
+ } else {
+ return {};
+ }
+ }
-inline optional<bool> toBool(const id value) {
- if (_isBool(value)) {
- return ((NSNumber *)value).boolValue;
- } else {
- return {};
+ static optional<std::string> toString(const Holder& holder) {
+ const id value = holder.value;
+ if (_isString(value)) {
+ return std::string(static_cast<const char *>([value UTF8String]));
+ } else {
+ return {};
+ }
}
-}
-inline optional<float> toNumber(const id value) {
- if (_isNumber(value)) {
- return ((NSNumber *)value).floatValue;
- } else {
- return {};
+ static optional<mbgl::Value> toValue(const Holder& holder) {
+ const id value = holder.value;
+ if (isUndefined(value)) {
+ return {};
+ } else if (_isBool(value)) {
+ return { *toBool(holder) };
+ } else if ( _isString(value)) {
+ return { *toString(holder) };
+ } else if (_isNumber(value)) {
+ // Need to cast to a double here as the float is otherwise considered a bool...
+ return { static_cast<double>(*toNumber(holder)) };
+ } else {
+ return {};
+ }
}
-}
-inline optional<double> toDouble(const id value) {
- if (_isNumber(value)) {
- return ((NSNumber *)value).doubleValue;
- } else {
+ static optional<GeoJSON> toGeoJSON(const Holder& holder, Error& error) {
+ error = { "toGeoJSON not implemented" };
return {};
}
-}
-inline optional<std::string> toString(const id value) {
- if (_isString(value)) {
- return std::string(static_cast<const char *>([value UTF8String]));
- } else {
- return {};
+private:
+ static bool _isBool(const id value) {
+ if (![value isKindOfClass:[NSNumber class]]) return false;
+ // char: 32-bit boolean
+ // BOOL: 64-bit boolean
+ NSNumber *number = value;
+ return ((strcmp([number objCType], @encode(char)) == 0) ||
+ (strcmp([number objCType], @encode(BOOL)) == 0));
}
-}
-inline optional<mbgl::Value> toValue(const id value) {
- if (isUndefined(value)) {
- return {};
- } else if (_isBool(value)) {
- return { *toBool(value) };
- } else if ( _isString(value)) {
- return { *toString(value) };
- } else if (_isNumber(value)) {
- // Need to cast to a double here as the float is otherwise considered a bool...
- return { static_cast<double>(*toNumber(value)) };
- } else {
- return {};
+ static bool _isNumber(const id value) {
+ return [value isKindOfClass:[NSNumber class]] && !_isBool(value);
}
+
+ static bool _isString(const id value) {
+ return [value isKindOfClass:[NSString class]];
+ }
+};
+
+inline Convertible makeConvertible(const id value) {
+ return Convertible(Holder(value));
}
} // namespace conversion
@@ -140,4 +158,3 @@ inline optional<mbgl::Value> toValue(const id value) {
} // namespace mbgl
NS_ASSUME_NONNULL_END
-
diff --git a/platform/darwin/src/MGLFeature.h b/platform/darwin/src/MGLFeature.h
index a13821cf96..62471abb16 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
@@ -148,7 +148,7 @@ NS_ASSUME_NONNULL_BEGIN
when the feature instance is used to initialize an `MGLShapeSource` and that
source is added to the map and styled.
*/
-@property (nonatomic, copy) NS_DICTIONARY_OF(NSString *, id) *attributes;
+@property (nonatomic, copy) NSDictionary<NSString *, id> *attributes;
/**
Returns the feature attribute for the given attribute name.
@@ -167,7 +167,7 @@ NS_ASSUME_NONNULL_BEGIN
`attributes` property, and an `id` key corresponding to the receiver’s
`identifier` property.
*/
-- (NS_DICTIONARY_OF(NSString *, id) *)geoJSONDictionary;
+- (NSDictionary<NSString *, id> *)geoJSONDictionary;
@end
@@ -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>
@@ -251,9 +252,9 @@ MGL_EXPORT
MGL_EXPORT
@interface MGLShapeCollectionFeature : MGLShapeCollection <MGLFeature>
-@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLShape<MGLFeature> *) *shapes;
+@property (nonatomic, copy, readonly) NSArray<MGLShape<MGLFeature> *> *shapes;
-+ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)shapes;
++ (instancetype)shapeCollectionWithShapes:(NSArray<MGLShape<MGLFeature> *> *)shapes;
@end
diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm
index 84f1a1ff25..02f67dca6e 100644
--- a/platform/darwin/src/MGLFeature.mm
+++ b/platform/darwin/src/MGLFeature.mm
@@ -7,12 +7,12 @@
#import "MGLShape_Private.h"
#import "MGLPointCollection_Private.h"
-#import "MGLPolyline+MGLAdditions.h"
-#import "MGLPolygon+MGLAdditions.h"
+#import "MGLPolyline_Private.h"
+#import "MGLPolygon_Private.h"
+
#import "NSDictionary+MGLAdditions.h"
#import "NSArray+MGLAdditions.h"
-
-#import "NSExpression+MGLAdditions.h"
+#import "NSExpression+MGLPrivateAdditions.h"
#import <mbgl/util/geometry.hpp>
#import <mbgl/style/conversion/geojson.hpp>
@@ -233,7 +233,7 @@ MGL_DEFINE_FEATURE_IS_EQUAL();
@dynamic shapes;
-+ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)shapes {
++ (instancetype)shapeCollectionWithShapes:(NSArray<MGLShape<MGLFeature> *> *)shapes {
return [super shapeCollectionWithShapes:shapes];
}
@@ -373,7 +373,7 @@ public:
}
};
-NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features) {
+NSArray<MGLShape <MGLFeature> *> *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features) {
NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:features.size()];
for (const auto &feature : features) {
[shapes addObject:MGLFeatureFromMBGLFeature(feature)];
@@ -414,7 +414,7 @@ mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *at
return feature;
}
-NS_DICTIONARY_OF(NSString *, id) *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier) {
+NSDictionary<NSString *, id> *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier) {
NSMutableDictionary *feature = [@{@"type": @"Feature",
@"properties": (attributes) ?: [NSNull null],
@"geometry": geometry} mutableCopy];
diff --git a/platform/darwin/src/MGLFeature_Private.h b/platform/darwin/src/MGLFeature_Private.h
index 4137200b98..d4074b53ed 100644
--- a/platform/darwin/src/MGLFeature_Private.h
+++ b/platform/darwin/src/MGLFeature_Private.h
@@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
vector tile features.
*/
MGL_EXPORT
-NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features);
+NSArray<MGLShape <MGLFeature> *> *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features);
/**
Returns an `MGLFeature` object converted from the given mbgl::Feature
@@ -36,7 +36,7 @@ mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *at
/**
Returns an `NSDictionary` representation of an `MGLFeature`.
*/
-NS_DICTIONARY_OF(NSString *, id) *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier);
+NSDictionary<NSString *, id> *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier);
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLFillExtrusionStyleLayer.h b/platform/darwin/src/MGLFillExtrusionStyleLayer.h
index c4fb9aa77e..7c3a0773e4 100644
--- a/platform/darwin/src/MGLFillExtrusionStyleLayer.h
+++ b/platform/darwin/src/MGLFillExtrusionStyleLayer.h
@@ -2,13 +2,13 @@
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLFoundation.h"
-#import "MGLStyleValue.h"
#import "MGLVectorStyleLayer.h"
NS_ASSUME_NONNULL_BEGIN
/**
- Controls the translation reference point.
+ Controls the frame of reference for
+ `MGLFillExtrusionStyleLayer.fillExtrusionTranslation`.
Values of this type are used in the `MGLFillExtrusionStyleLayer.fillExtrusionTranslationAnchor`
property.
@@ -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;
@@ -44,8 +45,8 @@ typedef NS_ENUM(NSUInteger, MGLFillExtrusionTranslationAnchor) {
```swift
let layer = MGLFillExtrusionStyleLayer(identifier: "buildings", source: buildings)
layer.sourceLayerIdentifier = "building"
- layer.fillExtrusionHeight = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "height", options: nil)
- layer.fillExtrusionBase = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "min_height", options: nil)
+ layer.fillExtrusionHeight = NSExpression(forKeyPath: "height")
+ layer.fillExtrusionBase = NSExpression(forKeyPath: "min_height")
layer.predicate = NSPredicate(format: "extrude == 'true'")
mapView.style?.addLayer(layer)
```
@@ -76,30 +77,22 @@ MGL_EXPORT
This property is measured in meters.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
+ 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.
This property is only applied to the style if `fillExtrusionHeight` is
non-`nil`. Otherwise, it is ignored.
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values no less than 0
+ * 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) MGLStyleValue<NSNumber *> *fillExtrusionBase;
+@property (nonatomic, null_resettable) NSExpression *fillExtrusionBase;
/**
The transition affecting any changes to this layer’s `fillExtrusionBase` property.
@@ -115,30 +108,23 @@ MGL_EXPORT
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 `MGLStyleValue` object containing
+ The default value of this property is an expression that evaluates to
`UIColor.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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ You can set this property to an expression containing any of the following:
+
+ * Constant `UIColor` 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) MGLStyleValue<UIColor *> *fillExtrusionColor;
+@property (nonatomic, null_resettable) NSExpression *fillExtrusionColor;
#else
/**
The base color of this layer. The extrusion's surfaces will be shaded
@@ -146,30 +132,23 @@ MGL_EXPORT
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 `MGLStyleValue` object containing
+ 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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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) MGLStyleValue<NSColor *> *fillExtrusionColor;
+@property (nonatomic, null_resettable) NSExpression *fillExtrusionColor;
#endif
/**
@@ -184,27 +163,19 @@ MGL_EXPORT
This property is measured in meters.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
-
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values no less than 0
+ * 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) MGLStyleValue<NSNumber *> *fillExtrusionHeight;
+@property (nonatomic, null_resettable) NSExpression *fillExtrusionHeight;
/**
The transition affecting any changes to this layer’s `fillExtrusionHeight` property.
@@ -217,18 +188,21 @@ MGL_EXPORT
The opacity of the entire fill extrusion layer. This is rendered on a
per-layer, not per-feature, basis, and data-driven styling is not available.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `1`. Set this property to `nil` to reset
- it to the default value.
+ 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.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ * Constant numeric values between 0 and 1 inclusive
+ * 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) MGLStyleValue<NSNumber *> *fillExtrusionOpacity;
+@property (nonatomic, null_resettable) NSExpression *fillExtrusionOpacity;
/**
The transition affecting any changes to this layer’s `fillExtrusionOpacity` property.
@@ -242,13 +216,19 @@ MGL_EXPORT
seamless patterns, image width and height must be a factor of two (2, 4, 8,
..., 512).
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant string values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *fillExtrusionPattern;
+@property (nonatomic, null_resettable) NSExpression *fillExtrusionPattern;
/**
The transition affecting any changes to this layer’s `fillExtrusionPattern` property.
@@ -263,7 +243,7 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points downward. Set this property to `nil` to reset it to the default value.
@@ -271,21 +251,25 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-extrusion-translate"><code>fill-extrusion-translate</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant `CGVector` 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillExtrusionTranslation;
+@property (nonatomic, null_resettable) NSExpression *fillExtrusionTranslation;
#else
/**
The geometry's offset.
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points upward. Set this property to `nil` to reset it to the default value.
@@ -293,14 +277,18 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-extrusion-translate"><code>fill-extrusion-translate</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ * Constant `CGVector` 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) MGLStyleValue<NSValue *> *fillExtrusionTranslation;
+@property (nonatomic, null_resettable) NSExpression *fillExtrusionTranslation;
#endif
/**
@@ -310,14 +298,13 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition fillExtrusionTranslationTransition;
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillExtrusionTranslate __attribute__((unavailable("Use fillExtrusionTranslation instead.")));
+@property (nonatomic, null_resettable) NSExpression *fillExtrusionTranslate __attribute__((unavailable("Use fillExtrusionTranslation instead.")));
/**
- Controls the translation reference point.
+ Controls the frame of reference for `fillExtrusionTranslation`.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLFillExtrusionTranslationAnchorMap`. Set this
- property to `nil` to reset it to the default value.
+ The default value of this property is an expression that evaluates to `map`.
+ Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `fillExtrusionTranslation` is
non-`nil`. Otherwise, it is ignored.
@@ -326,15 +313,24 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-extrusion-translate-anchor"><code>fill-extrusion-translate-anchor</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant `MGLFillExtrusionTranslationAnchor` values
+ * Any of the following constant string values:
+ * `map`: The fill extrusion is translated relative to the map.
+ * `viewport`: The fill extrusion is translated relative to the viewport.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillExtrusionTranslationAnchor;
+@property (nonatomic, null_resettable) NSExpression *fillExtrusionTranslationAnchor;
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillExtrusionTranslateAnchor __attribute__((unavailable("Use fillExtrusionTranslationAnchor instead.")));
+@property (nonatomic, null_resettable) NSExpression *fillExtrusionTranslateAnchor __attribute__((unavailable("Use fillExtrusionTranslationAnchor instead.")));
@end
diff --git a/platform/darwin/src/MGLFillExtrusionStyleLayer.mm b/platform/darwin/src/MGLFillExtrusionStyleLayer.mm
index b00ed8e09f..688ce4c1ac 100644
--- a/platform/darwin/src/MGLFillExtrusionStyleLayer.mm
+++ b/platform/darwin/src/MGLFillExtrusionStyleLayer.mm
@@ -77,21 +77,21 @@ namespace mbgl {
#pragma mark - Accessing the Paint Attributes
-- (void)setFillExtrusionBase:(MGLStyleValue<NSNumber *> *)fillExtrusionBase {
+- (void)setFillExtrusionBase:(NSExpression *)fillExtrusionBase {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(fillExtrusionBase);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(fillExtrusionBase);
self.rawLayer->setFillExtrusionBase(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)fillExtrusionBase {
+- (NSExpression *)fillExtrusionBase {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillExtrusionBase();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultFillExtrusionBase());
+ propertyValue = self.rawLayer->getDefaultFillExtrusionBase();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setFillExtrusionBaseTransition:(MGLTransition )transition {
@@ -112,21 +112,21 @@ namespace mbgl {
return transition;
}
-- (void)setFillExtrusionColor:(MGLStyleValue<MGLColor *> *)fillExtrusionColor {
+- (void)setFillExtrusionColor:(NSExpression *)fillExtrusionColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(fillExtrusionColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<mbgl::Color>>(fillExtrusionColor);
self.rawLayer->setFillExtrusionColor(mbglValue);
}
-- (MGLStyleValue<MGLColor *> *)fillExtrusionColor {
+- (NSExpression *)fillExtrusionColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillExtrusionColor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultFillExtrusionColor());
+ propertyValue = self.rawLayer->getDefaultFillExtrusionColor();
}
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(propertyValue);
}
- (void)setFillExtrusionColorTransition:(MGLTransition )transition {
@@ -147,21 +147,21 @@ namespace mbgl {
return transition;
}
-- (void)setFillExtrusionHeight:(MGLStyleValue<NSNumber *> *)fillExtrusionHeight {
+- (void)setFillExtrusionHeight:(NSExpression *)fillExtrusionHeight {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(fillExtrusionHeight);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(fillExtrusionHeight);
self.rawLayer->setFillExtrusionHeight(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)fillExtrusionHeight {
+- (NSExpression *)fillExtrusionHeight {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillExtrusionHeight();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultFillExtrusionHeight());
+ propertyValue = self.rawLayer->getDefaultFillExtrusionHeight();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setFillExtrusionHeightTransition:(MGLTransition )transition {
@@ -182,21 +182,21 @@ namespace mbgl {
return transition;
}
-- (void)setFillExtrusionOpacity:(MGLStyleValue<NSNumber *> *)fillExtrusionOpacity {
+- (void)setFillExtrusionOpacity:(NSExpression *)fillExtrusionOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(fillExtrusionOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(fillExtrusionOpacity);
self.rawLayer->setFillExtrusionOpacity(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)fillExtrusionOpacity {
+- (NSExpression *)fillExtrusionOpacity {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillExtrusionOpacity();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultFillExtrusionOpacity());
+ propertyValue = self.rawLayer->getDefaultFillExtrusionOpacity();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setFillExtrusionOpacityTransition:(MGLTransition )transition {
@@ -217,21 +217,22 @@ namespace mbgl {
return transition;
}
-- (void)setFillExtrusionPattern:(MGLStyleValue<NSString *> *)fillExtrusionPattern {
+- (void)setFillExtrusionPattern:(NSExpression *)fillExtrusionPattern {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(fillExtrusionPattern);
+ auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue<mbgl::style::PropertyValue<std::string>>(fillExtrusionPattern);
self.rawLayer->setFillExtrusionPattern(mbglValue);
}
-- (MGLStyleValue<NSString *> *)fillExtrusionPattern {
+- (NSExpression *)fillExtrusionPattern {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillExtrusionPattern();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(self.rawLayer->getDefaultFillExtrusionPattern());
+ propertyValue = self.rawLayer->getDefaultFillExtrusionPattern();
}
- return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
+ NSExpression *expression = MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ return expression.mgl_expressionByReplacingTokensWithKeyPaths;
}
- (void)setFillExtrusionPatternTransition:(MGLTransition )transition {
@@ -252,21 +253,21 @@ namespace mbgl {
return transition;
}
-- (void)setFillExtrusionTranslation:(MGLStyleValue<NSValue *> *)fillExtrusionTranslation {
+- (void)setFillExtrusionTranslation:(NSExpression *)fillExtrusionTranslation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toInterpolatablePropertyValue(fillExtrusionTranslation);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue<mbgl::style::PropertyValue<std::array<float, 2>>>(fillExtrusionTranslation);
self.rawLayer->setFillExtrusionTranslate(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)fillExtrusionTranslation {
+- (NSExpression *)fillExtrusionTranslation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillExtrusionTranslate();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(self.rawLayer->getDefaultFillExtrusionTranslate());
+ propertyValue = self.rawLayer->getDefaultFillExtrusionTranslate();
}
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toExpression(propertyValue);
}
- (void)setFillExtrusionTranslationTransition:(MGLTransition )transition {
@@ -287,34 +288,34 @@ namespace mbgl {
return transition;
}
-- (void)setFillExtrusionTranslate:(MGLStyleValue<NSValue *> *)fillExtrusionTranslate {
+- (void)setFillExtrusionTranslate:(NSExpression *)fillExtrusionTranslate {
}
-- (MGLStyleValue<NSValue *> *)fillExtrusionTranslate {
+- (NSExpression *)fillExtrusionTranslate {
return self.fillExtrusionTranslation;
}
-- (void)setFillExtrusionTranslationAnchor:(MGLStyleValue<NSValue *> *)fillExtrusionTranslationAnchor {
+- (void)setFillExtrusionTranslationAnchor:(NSExpression *)fillExtrusionTranslationAnchor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillExtrusionTranslationAnchor>().toEnumPropertyValue(fillExtrusionTranslationAnchor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillExtrusionTranslationAnchor>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType>>(fillExtrusionTranslationAnchor);
self.rawLayer->setFillExtrusionTranslateAnchor(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)fillExtrusionTranslationAnchor {
+- (NSExpression *)fillExtrusionTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillExtrusionTranslateAnchor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillExtrusionTranslationAnchor>().toEnumStyleValue(self.rawLayer->getDefaultFillExtrusionTranslateAnchor());
+ propertyValue = self.rawLayer->getDefaultFillExtrusionTranslateAnchor();
}
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillExtrusionTranslationAnchor>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillExtrusionTranslationAnchor>().toExpression(propertyValue);
}
-- (void)setFillExtrusionTranslateAnchor:(MGLStyleValue<NSValue *> *)fillExtrusionTranslateAnchor {
+- (void)setFillExtrusionTranslateAnchor:(NSExpression *)fillExtrusionTranslateAnchor {
}
-- (MGLStyleValue<NSValue *> *)fillExtrusionTranslateAnchor {
+- (NSExpression *)fillExtrusionTranslateAnchor {
return self.fillExtrusionTranslationAnchor;
}
diff --git a/platform/darwin/src/MGLFillStyleLayer.h b/platform/darwin/src/MGLFillStyleLayer.h
index 6e3297bdec..90740223eb 100644
--- a/platform/darwin/src/MGLFillStyleLayer.h
+++ b/platform/darwin/src/MGLFillStyleLayer.h
@@ -2,13 +2,12 @@
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLFoundation.h"
-#import "MGLStyleValue.h"
#import "MGLVectorStyleLayer.h"
NS_ASSUME_NONNULL_BEGIN
/**
- Controls the translation reference point.
+ Controls the frame of reference for `MGLFillStyleLayer.fillTranslation`.
Values of this type are used in the `MGLFillStyleLayer.fillTranslationAnchor`
property.
@@ -29,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;
@@ -44,7 +44,7 @@ typedef NS_ENUM(NSUInteger, MGLFillTranslationAnchor) {
```swift
let layer = MGLFillStyleLayer(identifier: "parks", source: parks)
layer.sourceLayerIdentifier = "parks"
- layer.fillColor = MGLStyleValue(rawValue: .green)
+ layer.fillColor = NSExpression(forConstantValue: UIColor.green)
layer.predicate = NSPredicate(format: "type == %@", "national-park")
mapView.style?.addLayer(layer)
```
@@ -72,80 +72,71 @@ MGL_EXPORT
/**
Whether or not the fill should be antialiased.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing `YES`. Set this property to `nil` to reset it to
- the default value.
+ The default value of this property is an expression that evaluates to `YES`.
+ 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-fill-antialias"><code>fill-antialias</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ * Constant Boolean values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
+
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable, getter=isFillAntialiased) MGLStyleValue<NSNumber *> *fillAntialiased;
+@property (nonatomic, null_resettable, getter=isFillAntialiased) NSExpression *fillAntialiased;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *fillAntialias __attribute__((unavailable("Use fillAntialiased instead.")));
+@property (nonatomic, null_resettable) NSExpression *fillAntialias __attribute__((unavailable("Use fillAntialiased instead.")));
#if TARGET_OS_IPHONE
/**
The color of the filled part of this layer.
- The default value of this property is an `MGLStyleValue` object containing
+ The default value of this property is an expression that evaluates to
`UIColor.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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ You can set this property to an expression containing any of the following:
+
+ * Constant `UIColor` 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) MGLStyleValue<UIColor *> *fillColor;
+@property (nonatomic, null_resettable) NSExpression *fillColor;
#else
/**
The color of the filled part of this layer.
- The default value of this property is an `MGLStyleValue` object containing
+ 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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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) MGLStyleValue<NSColor *> *fillColor;
+@property (nonatomic, null_resettable) NSExpression *fillColor;
#endif
/**
@@ -159,27 +150,19 @@ MGL_EXPORT
The opacity of the entire fill layer. In contrast to the `fillColor`, this
value will also affect the 1pt stroke around the fill, if the stroke is used.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `1`. Set this property to `nil` to reset
- it to the default value.
-
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values between 0 and 1 inclusive
+ * 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) MGLStyleValue<NSNumber *> *fillOpacity;
+@property (nonatomic, null_resettable) NSExpression *fillOpacity;
/**
The transition affecting any changes to this layer’s `fillOpacity` property.
@@ -193,51 +176,37 @@ MGL_EXPORT
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 `MGLStyleValue` object containing an
- `NSNumber` object containing `YES`. Otherwise, it is ignored.
-
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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 `UIColor` 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) MGLStyleValue<UIColor *> *fillOutlineColor;
+@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 `MGLStyleValue` object containing an
- `NSNumber` object containing `YES`. Otherwise, it is ignored.
-
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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) MGLStyleValue<NSColor *> *fillOutlineColor;
+@property (nonatomic, null_resettable) NSExpression *fillOutlineColor;
#endif
/**
@@ -249,15 +218,22 @@ MGL_EXPORT
/**
Name of image in sprite to use for drawing image fills. For seamless patterns,
- image width and height must be a factor of two (2, 4, 8, ..., 512).
+ image width and height must be a factor of two (2, 4, 8, ..., 512). Note that
+ zoom-dependent expressions will be evaluated only at integer zoom levels.
+
+ You can set this property to an expression containing any of the following:
- You can set this property to an instance of:
+ * Constant string values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *fillPattern;
+@property (nonatomic, null_resettable) NSExpression *fillPattern;
/**
The transition affecting any changes to this layer’s `fillPattern` property.
@@ -272,7 +248,7 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points downward. Set this property to `nil` to reset it to the default value.
@@ -280,21 +256,25 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-translate"><code>fill-translate</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ * Constant `CGVector` 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) MGLStyleValue<NSValue *> *fillTranslation;
+@property (nonatomic, null_resettable) NSExpression *fillTranslation;
#else
/**
The geometry's offset.
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points upward. Set this property to `nil` to reset it to the default value.
@@ -302,14 +282,18 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-translate"><code>fill-translate</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant `CGVector` 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslation;
+@property (nonatomic, null_resettable) NSExpression *fillTranslation;
#endif
/**
@@ -319,14 +303,13 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition fillTranslationTransition;
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslate __attribute__((unavailable("Use fillTranslation instead.")));
+@property (nonatomic, null_resettable) NSExpression *fillTranslate __attribute__((unavailable("Use fillTranslation instead.")));
/**
- Controls the translation reference point.
+ Controls the frame of reference for `fillTranslation`.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLFillTranslationAnchorMap`. Set this property to
- `nil` to reset it to the default value.
+ The default value of this property is an expression that evaluates to `map`.
+ Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `fillTranslation` is non-`nil`.
Otherwise, it is ignored.
@@ -335,15 +318,24 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-translate-anchor"><code>fill-translate-anchor</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant `MGLFillTranslationAnchor` values
+ * Any of the following constant string values:
+ * `map`: The fill is translated relative to the map.
+ * `viewport`: The fill is translated relative to the viewport.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslationAnchor;
+@property (nonatomic, null_resettable) NSExpression *fillTranslationAnchor;
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslateAnchor __attribute__((unavailable("Use fillTranslationAnchor instead.")));
+@property (nonatomic, null_resettable) NSExpression *fillTranslateAnchor __attribute__((unavailable("Use fillTranslationAnchor instead.")));
@end
diff --git a/platform/darwin/src/MGLFillStyleLayer.mm b/platform/darwin/src/MGLFillStyleLayer.mm
index 71b01a6661..c975e28d6b 100644
--- a/platform/darwin/src/MGLFillStyleLayer.mm
+++ b/platform/darwin/src/MGLFillStyleLayer.mm
@@ -77,45 +77,45 @@ namespace mbgl {
#pragma mark - Accessing the Paint Attributes
-- (void)setFillAntialiased:(MGLStyleValue<NSNumber *> *)fillAntialiased {
+- (void)setFillAntialiased:(NSExpression *)fillAntialiased {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(fillAntialiased);
+ auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<bool>>(fillAntialiased);
self.rawLayer->setFillAntialias(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)isFillAntialiased {
+- (NSExpression *)isFillAntialiased {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillAntialias();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultFillAntialias());
+ propertyValue = self.rawLayer->getDefaultFillAntialias();
}
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<bool, NSNumber *>().toExpression(propertyValue);
}
-- (void)setFillAntialias:(MGLStyleValue<NSNumber *> *)fillAntialias {
+- (void)setFillAntialias:(NSExpression *)fillAntialias {
}
-- (MGLStyleValue<NSNumber *> *)fillAntialias {
+- (NSExpression *)fillAntialias {
return self.isFillAntialiased;
}
-- (void)setFillColor:(MGLStyleValue<MGLColor *> *)fillColor {
+- (void)setFillColor:(NSExpression *)fillColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(fillColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<mbgl::Color>>(fillColor);
self.rawLayer->setFillColor(mbglValue);
}
-- (MGLStyleValue<MGLColor *> *)fillColor {
+- (NSExpression *)fillColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillColor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultFillColor());
+ propertyValue = self.rawLayer->getDefaultFillColor();
}
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(propertyValue);
}
- (void)setFillColorTransition:(MGLTransition )transition {
@@ -136,21 +136,21 @@ namespace mbgl {
return transition;
}
-- (void)setFillOpacity:(MGLStyleValue<NSNumber *> *)fillOpacity {
+- (void)setFillOpacity:(NSExpression *)fillOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(fillOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(fillOpacity);
self.rawLayer->setFillOpacity(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)fillOpacity {
+- (NSExpression *)fillOpacity {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillOpacity();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultFillOpacity());
+ propertyValue = self.rawLayer->getDefaultFillOpacity();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setFillOpacityTransition:(MGLTransition )transition {
@@ -171,21 +171,21 @@ namespace mbgl {
return transition;
}
-- (void)setFillOutlineColor:(MGLStyleValue<MGLColor *> *)fillOutlineColor {
+- (void)setFillOutlineColor:(NSExpression *)fillOutlineColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(fillOutlineColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<mbgl::Color>>(fillOutlineColor);
self.rawLayer->setFillOutlineColor(mbglValue);
}
-- (MGLStyleValue<MGLColor *> *)fillOutlineColor {
+- (NSExpression *)fillOutlineColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillOutlineColor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultFillOutlineColor());
+ propertyValue = self.rawLayer->getDefaultFillOutlineColor();
}
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(propertyValue);
}
- (void)setFillOutlineColorTransition:(MGLTransition )transition {
@@ -206,21 +206,22 @@ namespace mbgl {
return transition;
}
-- (void)setFillPattern:(MGLStyleValue<NSString *> *)fillPattern {
+- (void)setFillPattern:(NSExpression *)fillPattern {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(fillPattern);
+ auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue<mbgl::style::PropertyValue<std::string>>(fillPattern);
self.rawLayer->setFillPattern(mbglValue);
}
-- (MGLStyleValue<NSString *> *)fillPattern {
+- (NSExpression *)fillPattern {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillPattern();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(self.rawLayer->getDefaultFillPattern());
+ propertyValue = self.rawLayer->getDefaultFillPattern();
}
- return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
+ NSExpression *expression = MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ return expression.mgl_expressionByReplacingTokensWithKeyPaths;
}
- (void)setFillPatternTransition:(MGLTransition )transition {
@@ -241,21 +242,21 @@ namespace mbgl {
return transition;
}
-- (void)setFillTranslation:(MGLStyleValue<NSValue *> *)fillTranslation {
+- (void)setFillTranslation:(NSExpression *)fillTranslation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toInterpolatablePropertyValue(fillTranslation);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue<mbgl::style::PropertyValue<std::array<float, 2>>>(fillTranslation);
self.rawLayer->setFillTranslate(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)fillTranslation {
+- (NSExpression *)fillTranslation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillTranslate();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(self.rawLayer->getDefaultFillTranslate());
+ propertyValue = self.rawLayer->getDefaultFillTranslate();
}
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toExpression(propertyValue);
}
- (void)setFillTranslationTransition:(MGLTransition )transition {
@@ -276,34 +277,34 @@ namespace mbgl {
return transition;
}
-- (void)setFillTranslate:(MGLStyleValue<NSValue *> *)fillTranslate {
+- (void)setFillTranslate:(NSExpression *)fillTranslate {
}
-- (MGLStyleValue<NSValue *> *)fillTranslate {
+- (NSExpression *)fillTranslate {
return self.fillTranslation;
}
-- (void)setFillTranslationAnchor:(MGLStyleValue<NSValue *> *)fillTranslationAnchor {
+- (void)setFillTranslationAnchor:(NSExpression *)fillTranslationAnchor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslationAnchor>().toEnumPropertyValue(fillTranslationAnchor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslationAnchor>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType>>(fillTranslationAnchor);
self.rawLayer->setFillTranslateAnchor(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)fillTranslationAnchor {
+- (NSExpression *)fillTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getFillTranslateAnchor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslationAnchor>().toEnumStyleValue(self.rawLayer->getDefaultFillTranslateAnchor());
+ propertyValue = self.rawLayer->getDefaultFillTranslateAnchor();
}
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslationAnchor>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslationAnchor>().toExpression(propertyValue);
}
-- (void)setFillTranslateAnchor:(MGLStyleValue<NSValue *> *)fillTranslateAnchor {
+- (void)setFillTranslateAnchor:(NSExpression *)fillTranslateAnchor {
}
-- (MGLStyleValue<NSValue *> *)fillTranslateAnchor {
+- (NSExpression *)fillTranslateAnchor {
return self.fillTranslationAnchor;
}
diff --git a/platform/darwin/src/MGLForegroundStyleLayer.h b/platform/darwin/src/MGLForegroundStyleLayer.h
index bcd323fb99..7e05023ef1 100644
--- a/platform/darwin/src/MGLForegroundStyleLayer.h
+++ b/platform/darwin/src/MGLForegroundStyleLayer.h
@@ -11,10 +11,11 @@ NS_ASSUME_NONNULL_BEGIN
`MGLForegroundStyleLayer` is an abstract superclass for style layers whose
content is defined by an `MGLSource` object.
- Create instances of `MGLRasterStyleLayer` and the concrete subclasses of
- `MGLVectorStyleLayer` in order to use `MGLForegroundStyleLayer`'s methods.
- Do not create instances of `MGLForegroundStyleLayer` directly, and do not
- create your own subclasses of this class.
+ Create instances of `MGLRasterStyleLayer`, `MGLHillshadeStyleLayer`, and the
+ concrete subclasses of `MGLVectorStyleLayer` in order to use
+ `MGLForegroundStyleLayer`'s methods. Do not create instances of
+ `MGLForegroundStyleLayer` directly, and do not create your own subclasses of
+ this class.
*/
MGL_EXPORT
@interface MGLForegroundStyleLayer : MGLStyleLayer
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
new file mode 100644
index 0000000000..ad7ba5de01
--- /dev/null
+++ b/platform/darwin/src/MGLHeatmapStyleLayer.h
@@ -0,0 +1,215 @@
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
+
+#import "MGLFoundation.h"
+#import "MGLVectorStyleLayer.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ An `MGLHeatmapStyleLayer` is a style layer that renders a <a
+ href="https://en.wikipedia.org/wiki/Heat_map">heatmap</a>.
+
+ 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. 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
+ data in an `MGLShapeSource` is dense enough to warrant a heatmap, you can
+ alternatively cluster the source using the `MGLShapeSourceOptionClustered`
+ option and render the data using an `MGLCircleStyleLayer` or
+ `MGLSymbolStyleLayer`.
+
+ You can access an existing heatmap style layer using the
+ `-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
+ otherwise, find it using the `MGLStyle.layers` property. You can also create a
+ new heatmap style layer and add it to the style using a method such as
+ `-[MGLStyle addLayer:]`.
+
+ ### Example
+
+ ```swift
+ let layer = MGLHeatmapStyleLayer(identifier: "earthquake-heat", source: earthquakes)
+ layer.heatmapWeight = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:(magnitude, 'linear', nil, %@)",
+ [0: 0,
+ 6: 1])
+ layer.heatmapIntensity = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)",
+ [0: 1,
+ 9: 3])
+ mapView.style?.addLayer(layer)
+ ```
+ */
+MGL_EXPORT
+@interface MGLHeatmapStyleLayer : MGLVectorStyleLayer
+
+/**
+ Returns a heatmap style layer initialized with an identifier and source.
+
+ After initializing and configuring the style layer, add it to a map view’s
+ style using the `-[MGLStyle addLayer:]` or
+ `-[MGLStyle insertLayer:belowLayer:]` method.
+
+ @param identifier A string that uniquely identifies the source in the style to
+ which it is added.
+ @param source The source from which to obtain the data to style. If the source
+ has not yet been added to the current style, the behavior is undefined.
+ @return An initialized foreground style layer.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source;
+
+#pragma mark - Accessing the Paint Attributes
+
+#if TARGET_OS_IPHONE
+/**
+ 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 `UIColor` 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;
+#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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values no less than 0
+ * 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 *heatmapIntensity;
+
+/**
+ The transition affecting any changes to this layer’s `heatmapIntensity` property.
+
+ This property corresponds to the `heatmap-intensity-transition` property in the style JSON file format.
+*/
+@property (nonatomic) MGLTransition heatmapIntensityTransition;
+
+/**
+ 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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values between 0 and 1 inclusive
+ * 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 *heatmapOpacity;
+
+/**
+ The transition affecting any changes to this layer’s `heatmapOpacity` property.
+
+ This property corresponds to the `heatmap-opacity-transition` property in the style JSON file format.
+*/
+@property (nonatomic) MGLTransition heatmapOpacityTransition;
+
+/**
+ Radius of influence of one heatmap point in points. Increasing the value makes
+ the heatmap smoother, but less detailed.
+
+ 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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values no less than 1
+ * 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 *heatmapRadius;
+
+/**
+ The transition affecting any changes to this layer’s `heatmapRadius` property.
+
+ This property corresponds to the `heatmap-radius-transition` property in the style JSON file format.
+*/
+@property (nonatomic) MGLTransition heatmapRadiusTransition;
+
+/**
+ A measure of how much an individual point contributes to the heatmap. A value
+ of 10 would be equivalent to having 10 points of weight 1 in the same spot.
+ 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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values no less than 0
+ * 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 *heatmapWeight;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLHeatmapStyleLayer.mm b/platform/darwin/src/MGLHeatmapStyleLayer.mm
new file mode 100644
index 0000000000..a394dbda3b
--- /dev/null
+++ b/platform/darwin/src/MGLHeatmapStyleLayer.mm
@@ -0,0 +1,210 @@
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
+
+#import "MGLSource.h"
+#import "NSPredicate+MGLAdditions.h"
+#import "NSDate+MGLAdditions.h"
+#import "MGLStyleLayer_Private.h"
+#import "MGLStyleValue_Private.h"
+#import "MGLHeatmapStyleLayer.h"
+
+#include <mbgl/style/transition_options.hpp>
+#include <mbgl/style/layers/heatmap_layer.hpp>
+
+@interface MGLHeatmapStyleLayer ()
+
+@property (nonatomic, readonly) mbgl::style::HeatmapLayer *rawLayer;
+
+@end
+
+@implementation MGLHeatmapStyleLayer
+
+- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source
+{
+ auto layer = std::make_unique<mbgl::style::HeatmapLayer>(identifier.UTF8String, source.identifier.UTF8String);
+ return self = [super initWithPendingLayer:std::move(layer)];
+}
+
+- (mbgl::style::HeatmapLayer *)rawLayer
+{
+ return (mbgl::style::HeatmapLayer *)super.rawLayer;
+}
+
+- (NSString *)sourceIdentifier
+{
+ MGLAssertStyleLayerIsValid();
+
+ return @(self.rawLayer->getSourceID().c_str());
+}
+
+- (NSString *)sourceLayerIdentifier
+{
+ MGLAssertStyleLayerIsValid();
+
+ auto layerID = self.rawLayer->getSourceLayer();
+ return layerID.empty() ? nil : @(layerID.c_str());
+}
+
+- (void)setSourceLayerIdentifier:(NSString *)sourceLayerIdentifier
+{
+ MGLAssertStyleLayerIsValid();
+
+ self.rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: "");
+}
+
+- (void)setPredicate:(NSPredicate *)predicate
+{
+ MGLAssertStyleLayerIsValid();
+
+ self.rawLayer->setFilter(predicate ? predicate.mgl_filter : mbgl::style::NullFilter());
+}
+
+- (NSPredicate *)predicate
+{
+ MGLAssertStyleLayerIsValid();
+
+ return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()];
+}
+
+#pragma mark - Accessing the Paint Attributes
+
+- (void)setHeatmapColor:(NSExpression *)heatmapColor {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::HeatmapColorPropertyValue>(heatmapColor);
+ self.rawLayer->setHeatmapColor(mbglValue);
+}
+
+- (NSExpression *)heatmapColor {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getHeatmapColor();
+ if (propertyValue.isUndefined()) {
+ propertyValue = self.rawLayer->getDefaultHeatmapColor();
+ }
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(propertyValue);
+}
+
+- (void)setHeatmapIntensity:(NSExpression *)heatmapIntensity {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(heatmapIntensity);
+ self.rawLayer->setHeatmapIntensity(mbglValue);
+}
+
+- (NSExpression *)heatmapIntensity {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getHeatmapIntensity();
+ if (propertyValue.isUndefined()) {
+ propertyValue = self.rawLayer->getDefaultHeatmapIntensity();
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
+}
+
+- (void)setHeatmapIntensityTransition:(MGLTransition )transition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
+ self.rawLayer->setHeatmapIntensityTransition(options);
+}
+
+- (MGLTransition)heatmapIntensityTransition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getHeatmapIntensityTransition();
+ MGLTransition transition;
+ transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
+ transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
+
+ return transition;
+}
+
+- (void)setHeatmapOpacity:(NSExpression *)heatmapOpacity {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(heatmapOpacity);
+ self.rawLayer->setHeatmapOpacity(mbglValue);
+}
+
+- (NSExpression *)heatmapOpacity {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getHeatmapOpacity();
+ if (propertyValue.isUndefined()) {
+ propertyValue = self.rawLayer->getDefaultHeatmapOpacity();
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
+}
+
+- (void)setHeatmapOpacityTransition:(MGLTransition )transition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
+ self.rawLayer->setHeatmapOpacityTransition(options);
+}
+
+- (MGLTransition)heatmapOpacityTransition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getHeatmapOpacityTransition();
+ MGLTransition transition;
+ transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
+ transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
+
+ return transition;
+}
+
+- (void)setHeatmapRadius:(NSExpression *)heatmapRadius {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(heatmapRadius);
+ self.rawLayer->setHeatmapRadius(mbglValue);
+}
+
+- (NSExpression *)heatmapRadius {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getHeatmapRadius();
+ if (propertyValue.isUndefined()) {
+ propertyValue = self.rawLayer->getDefaultHeatmapRadius();
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
+}
+
+- (void)setHeatmapRadiusTransition:(MGLTransition )transition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
+ self.rawLayer->setHeatmapRadiusTransition(options);
+}
+
+- (MGLTransition)heatmapRadiusTransition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getHeatmapRadiusTransition();
+ MGLTransition transition;
+ transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
+ transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
+
+ return transition;
+}
+
+- (void)setHeatmapWeight:(NSExpression *)heatmapWeight {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(heatmapWeight);
+ self.rawLayer->setHeatmapWeight(mbglValue);
+}
+
+- (NSExpression *)heatmapWeight {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getHeatmapWeight();
+ if (propertyValue.isUndefined()) {
+ propertyValue = self.rawLayer->getDefaultHeatmapWeight();
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
+}
+
+@end
diff --git a/platform/darwin/src/MGLHillshadeStyleLayer.h b/platform/darwin/src/MGLHillshadeStyleLayer.h
new file mode 100644
index 0000000000..224680160a
--- /dev/null
+++ b/platform/darwin/src/MGLHillshadeStyleLayer.h
@@ -0,0 +1,324 @@
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
+
+#import "MGLFoundation.h"
+#import "MGLForegroundStyleLayer.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Direction of light source when map is rotated.
+
+ Values of this type are used in the `MGLHillshadeStyleLayer.hillshadeIlluminationAnchor`
+ property.
+ */
+typedef NS_ENUM(NSUInteger, MGLHillshadeIlluminationAnchor) {
+ /**
+ The hillshade illumination is relative to the north direction.
+ */
+ MGLHillshadeIlluminationAnchorMap,
+ /**
+ The hillshade illumination is relative to the top of the viewport.
+ */
+ MGLHillshadeIlluminationAnchorViewport,
+};
+
+/**
+ An `MGLHillshadeStyleLayer` is a style layer that renders raster <a
+ href="https://en.wikipedia.org/wiki/Digital_elevation_model">digital elevation
+ model</a> (DEM) tiles on the map.
+
+ Use a hillshade style layer to configure the color parameters of raster tiles
+ loaded by an `MGLRasterDEMSource` object. For example, you could use a
+ hillshade style layer to render <a
+ href="https://www.mapbox.com/help/access-elevation-data/#mapbox-terrain-rgb">Mapbox
+ Terrain-RGB</a> data.
+
+ 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 `MGLVectorTileSource` object in conjunction with several
+ `MGLFillStyleLayer` objects.
+
+ You can access an existing hillshade style layer using the
+ `-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
+ otherwise, find it using the `MGLStyle.layers` property. You can also create a
+ new hillshade style layer and add it to the style using a method such as
+ `-[MGLStyle addLayer:]`.
+
+ ### Example
+
+ ```swift
+ let layer = MGLHillshadeStyleLayer(identifier: "hills", source: source)
+ layer.hillshadeExaggeration = NSExpression(forConstantValue: 0.6)
+ if let canalShadowLayer = mapView.style?.layer(withIdentifier: "waterway-river-canal-shadow") {
+ mapView.style?.insertLayer(layer, below: canalShadowLayer)
+ }
+ ```
+ */
+MGL_EXPORT
+@interface MGLHillshadeStyleLayer : MGLForegroundStyleLayer
+
+/**
+ Returns a hillshade style layer initialized with an identifier and source.
+
+ After initializing and configuring the style layer, add it to a map view’s
+ style using the `-[MGLStyle addLayer:]` or
+ `-[MGLStyle insertLayer:belowLayer:]` method.
+
+ @param identifier A string that uniquely identifies the source in the style to
+ which it is added.
+ @param source The source from which to obtain the data to style. If the source
+ has not yet been added to the current style, the behavior is undefined.
+ @return An initialized foreground style layer.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source;
+
+#pragma mark - Accessing the Paint Attributes
+
+#if TARGET_OS_IPHONE
+/**
+ 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
+ `UIColor.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 `UIColor` 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;
+#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.
+
+ This property corresponds to the `hillshade-accent-color-transition` property in the style JSON file format.
+*/
+@property (nonatomic) MGLTransition hillshadeAccentColorTransition;
+
+/**
+ 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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values between 0 and 1 inclusive
+ * 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 *hillshadeExaggeration;
+
+/**
+ The transition affecting any changes to this layer’s `hillshadeExaggeration` property.
+
+ This property corresponds to the `hillshade-exaggeration-transition` property in the style JSON file format.
+*/
+@property (nonatomic) MGLTransition hillshadeExaggerationTransition;
+
+#if TARGET_OS_IPHONE
+/**
+ The shading color of areas that faces towards the light source.
+
+ The default value of this property is an expression that evaluates to
+ `UIColor.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 `UIColor` 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;
+#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.
+
+ This property corresponds to the `hillshade-highlight-color-transition` property in the style JSON file format.
+*/
+@property (nonatomic) MGLTransition hillshadeHighlightColorTransition;
+
+/**
+ Direction of light source when map is rotated.
+
+ The default value of this property is an expression that evaluates to
+ `viewport`. 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 `MGLHillshadeIlluminationAnchor` values
+ * Any of the following constant string values:
+ * `map`: The hillshade illumination is relative to the north direction.
+ * `viewport`: The hillshade illumination is relative to the top of the
+ viewport.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
+
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
+ */
+@property (nonatomic, null_resettable) NSExpression *hillshadeIlluminationAnchor;
+
+/**
+ The direction of the light source used to generate the hillshading with 0 as
+ the top of the viewport if `hillshadeIlluminationAnchor` is set to
+ `MGLHillshadeIlluminationAnchorViewport` and due north if
+ `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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values between 0 and 359 inclusive
+ * 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 *hillshadeIlluminationDirection;
+
+#if TARGET_OS_IPHONE
+/**
+ The shading color of areas that face away from the light source.
+
+ The default value of this property is an expression that evaluates to
+ `UIColor.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 `UIColor` 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;
+#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.
+
+ This property corresponds to the `hillshade-shadow-color-transition` property in the style JSON file format.
+*/
+@property (nonatomic) MGLTransition hillshadeShadowColorTransition;
+
+@end
+
+/**
+ Methods for wrapping an enumeration value for a style layer attribute in an
+ `MGLHillshadeStyleLayer` object and unwrapping its raw value.
+ */
+@interface NSValue (MGLHillshadeStyleLayerAdditions)
+
+#pragma mark Working with Hillshade Style Layer Attribute Values
+
+/**
+ Creates a new value object containing the given `MGLHillshadeIlluminationAnchor` enumeration.
+
+ @param hillshadeIlluminationAnchor The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLHillshadeIlluminationAnchor:(MGLHillshadeIlluminationAnchor)hillshadeIlluminationAnchor;
+
+/**
+ The `MGLHillshadeIlluminationAnchor` enumeration representation of the value.
+ */
+@property (readonly) MGLHillshadeIlluminationAnchor MGLHillshadeIlluminationAnchorValue;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLHillshadeStyleLayer.mm b/platform/darwin/src/MGLHillshadeStyleLayer.mm
new file mode 100644
index 0000000000..2383c1ce26
--- /dev/null
+++ b/platform/darwin/src/MGLHillshadeStyleLayer.mm
@@ -0,0 +1,239 @@
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
+
+#import "MGLSource.h"
+#import "NSPredicate+MGLAdditions.h"
+#import "NSDate+MGLAdditions.h"
+#import "MGLStyleLayer_Private.h"
+#import "MGLStyleValue_Private.h"
+#import "MGLHillshadeStyleLayer.h"
+
+#include <mbgl/style/transition_options.hpp>
+#include <mbgl/style/layers/hillshade_layer.hpp>
+
+namespace mbgl {
+
+ MBGL_DEFINE_ENUM(MGLHillshadeIlluminationAnchor, {
+ { MGLHillshadeIlluminationAnchorMap, "map" },
+ { MGLHillshadeIlluminationAnchorViewport, "viewport" },
+ });
+
+}
+
+@interface MGLHillshadeStyleLayer ()
+
+@property (nonatomic, readonly) mbgl::style::HillshadeLayer *rawLayer;
+
+@end
+
+@implementation MGLHillshadeStyleLayer
+
+- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source
+{
+ auto layer = std::make_unique<mbgl::style::HillshadeLayer>(identifier.UTF8String, source.identifier.UTF8String);
+ return self = [super initWithPendingLayer:std::move(layer)];
+}
+
+- (mbgl::style::HillshadeLayer *)rawLayer
+{
+ return (mbgl::style::HillshadeLayer *)super.rawLayer;
+}
+
+- (NSString *)sourceIdentifier
+{
+ MGLAssertStyleLayerIsValid();
+
+ return @(self.rawLayer->getSourceID().c_str());
+}
+
+#pragma mark - Accessing the Paint Attributes
+
+- (void)setHillshadeAccentColor:(NSExpression *)hillshadeAccentColor {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::PropertyValue<mbgl::Color>>(hillshadeAccentColor);
+ self.rawLayer->setHillshadeAccentColor(mbglValue);
+}
+
+- (NSExpression *)hillshadeAccentColor {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getHillshadeAccentColor();
+ if (propertyValue.isUndefined()) {
+ propertyValue = self.rawLayer->getDefaultHillshadeAccentColor();
+ }
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(propertyValue);
+}
+
+- (void)setHillshadeAccentColorTransition:(MGLTransition )transition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
+ self.rawLayer->setHillshadeAccentColorTransition(options);
+}
+
+- (MGLTransition)hillshadeAccentColorTransition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getHillshadeAccentColorTransition();
+ MGLTransition transition;
+ transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
+ transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
+
+ return transition;
+}
+
+- (void)setHillshadeExaggeration:(NSExpression *)hillshadeExaggeration {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(hillshadeExaggeration);
+ self.rawLayer->setHillshadeExaggeration(mbglValue);
+}
+
+- (NSExpression *)hillshadeExaggeration {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getHillshadeExaggeration();
+ if (propertyValue.isUndefined()) {
+ propertyValue = self.rawLayer->getDefaultHillshadeExaggeration();
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
+}
+
+- (void)setHillshadeExaggerationTransition:(MGLTransition )transition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
+ self.rawLayer->setHillshadeExaggerationTransition(options);
+}
+
+- (MGLTransition)hillshadeExaggerationTransition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getHillshadeExaggerationTransition();
+ MGLTransition transition;
+ transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
+ transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
+
+ return transition;
+}
+
+- (void)setHillshadeHighlightColor:(NSExpression *)hillshadeHighlightColor {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::PropertyValue<mbgl::Color>>(hillshadeHighlightColor);
+ self.rawLayer->setHillshadeHighlightColor(mbglValue);
+}
+
+- (NSExpression *)hillshadeHighlightColor {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getHillshadeHighlightColor();
+ if (propertyValue.isUndefined()) {
+ propertyValue = self.rawLayer->getDefaultHillshadeHighlightColor();
+ }
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(propertyValue);
+}
+
+- (void)setHillshadeHighlightColorTransition:(MGLTransition )transition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
+ self.rawLayer->setHillshadeHighlightColorTransition(options);
+}
+
+- (MGLTransition)hillshadeHighlightColorTransition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getHillshadeHighlightColorTransition();
+ MGLTransition transition;
+ transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
+ transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
+
+ return transition;
+}
+
+- (void)setHillshadeIlluminationAnchor:(NSExpression *)hillshadeIlluminationAnchor {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::HillshadeIlluminationAnchorType, NSValue *, mbgl::style::HillshadeIlluminationAnchorType, MGLHillshadeIlluminationAnchor>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::HillshadeIlluminationAnchorType>>(hillshadeIlluminationAnchor);
+ self.rawLayer->setHillshadeIlluminationAnchor(mbglValue);
+}
+
+- (NSExpression *)hillshadeIlluminationAnchor {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getHillshadeIlluminationAnchor();
+ if (propertyValue.isUndefined()) {
+ propertyValue = self.rawLayer->getDefaultHillshadeIlluminationAnchor();
+ }
+ return MGLStyleValueTransformer<mbgl::style::HillshadeIlluminationAnchorType, NSValue *, mbgl::style::HillshadeIlluminationAnchorType, MGLHillshadeIlluminationAnchor>().toExpression(propertyValue);
+}
+
+- (void)setHillshadeIlluminationDirection:(NSExpression *)hillshadeIlluminationDirection {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(hillshadeIlluminationDirection);
+ self.rawLayer->setHillshadeIlluminationDirection(mbglValue);
+}
+
+- (NSExpression *)hillshadeIlluminationDirection {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getHillshadeIlluminationDirection();
+ if (propertyValue.isUndefined()) {
+ propertyValue = self.rawLayer->getDefaultHillshadeIlluminationDirection();
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
+}
+
+- (void)setHillshadeShadowColor:(NSExpression *)hillshadeShadowColor {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::PropertyValue<mbgl::Color>>(hillshadeShadowColor);
+ self.rawLayer->setHillshadeShadowColor(mbglValue);
+}
+
+- (NSExpression *)hillshadeShadowColor {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getHillshadeShadowColor();
+ if (propertyValue.isUndefined()) {
+ propertyValue = self.rawLayer->getDefaultHillshadeShadowColor();
+ }
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(propertyValue);
+}
+
+- (void)setHillshadeShadowColorTransition:(MGLTransition )transition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
+ self.rawLayer->setHillshadeShadowColorTransition(options);
+}
+
+- (MGLTransition)hillshadeShadowColorTransition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getHillshadeShadowColorTransition();
+ MGLTransition transition;
+ transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
+ transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
+
+ return transition;
+}
+
+@end
+
+@implementation NSValue (MGLHillshadeStyleLayerAdditions)
+
++ (NSValue *)valueWithMGLHillshadeIlluminationAnchor:(MGLHillshadeIlluminationAnchor)hillshadeIlluminationAnchor {
+ return [NSValue value:&hillshadeIlluminationAnchor withObjCType:@encode(MGLHillshadeIlluminationAnchor)];
+}
+
+- (MGLHillshadeIlluminationAnchor)MGLHillshadeIlluminationAnchorValue {
+ MGLHillshadeIlluminationAnchor hillshadeIlluminationAnchor;
+ [self getValue:&hillshadeIlluminationAnchor];
+ return hillshadeIlluminationAnchor;
+}
+
+@end
diff --git a/platform/darwin/src/MGLLight.h b/platform/darwin/src/MGLLight.h
index 55b789f043..cf4aa50112 100644
--- a/platform/darwin/src/MGLLight.h
+++ b/platform/darwin/src/MGLLight.h
@@ -27,7 +27,7 @@ typedef NS_ENUM(NSUInteger, MGLLightAnchor) {
A structure containing information about the position of the light source
relative to lit geometries.
*/
-typedef struct MGLSphericalPosition {
+typedef struct __attribute__((objc_boxable)) MGLSphericalPosition {
/** Distance from the center of the base of an object to its light. */
CGFloat radial;
/** Position of the light relative to 0° (0° when `MGLLight.anchor` is set to viewport corresponds
@@ -65,20 +65,31 @@ MGL_EXPORT
/**
Whether extruded geometries are lit relative to the map or viewport.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLLightAnchorViewport`.
+ The default value of this property is an expression that evaluates to
+ `viewport`.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ * Constant `MGLAnchor` values
+ * Any of the following constant string values:
+ * `map`: The position of the light source is aligned to the rotation of the
+ map.
+ * `viewport`: The position of the light source is aligned to the rotation of
+ the viewport.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
+
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or 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-anchor"><code>anchor</code></a>
light property in the Mapbox Style Specification.
*/
-@property (nonatomic) MGLStyleValue<NSValue *> *anchor;
+@property (nonatomic) NSExpression *anchor;
/**
Position of the `MGLLight` source relative to lit (extruded) geometries, in a
@@ -90,21 +101,25 @@ MGL_EXPORT
corresponds to due north, and degrees proceed clockwise), and polar indicates
the height of the light (from 0°, directly above, to 180°, directly below).
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`MGLSphericalPosition` struct set to 1.15 radial, 210 azimuthal and 30 polar.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant `MGLSphericalPosition` 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ 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-position"><code>position</code></a>
light property in the Mapbox Style Specification.
*/
-@property (nonatomic) MGLStyleValue<NSValue *> *position;
+@property (nonatomic) NSExpression *position;
/**
The transition affecting any changes to this layer’s `position` property.
@@ -117,40 +132,48 @@ MGL_EXPORT
/**
Color tint for lighting extruded geometries.
- The default value of this property is an `MGLStyleValue` object containing
+ The default value of this property is an expression that evaluates to
`UIColor.whiteColor`.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant `UIColor` 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ 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) MGLStyleValue<UIColor *> *color;
+@property (nonatomic) NSExpression *color;
#else
/**
Color tint for lighting extruded geometries.
- The default value of this property is an `MGLStyleValue` object containing
+ The default value of this property is an expression that evaluates to
`NSColor.whiteColor`.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ * 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) MGLStyleValue<NSColor *> *color;
+@property (nonatomic) NSExpression *color;
#endif
/**
@@ -164,21 +187,25 @@ MGL_EXPORT
Intensity of lighting (on a scale from 0 to 1). Higher numbers will present as
more extreme contrast.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0.5`.
+ The default value of this property is an expression that evaluates to the float
+ 0.5.
+
+ You can set this property to an expression containing any of the following:
- You can set this property to an instance of:
+ * Constant numeric values between 0 and 1 inclusive
+ * 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ 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-intensity"><code>intensity</code></a>
light property in the Mapbox Style Specification.
*/
-@property (nonatomic) MGLStyleValue<NSNumber *> *intensity;
+@property (nonatomic) NSExpression *intensity;
/**
The transition affecting any changes to this layer’s `intensity` property.
diff --git a/platform/darwin/src/MGLLight.h.ejs b/platform/darwin/src/MGLLight.h.ejs
index 26ecefc3af..56c3312107 100644
--- a/platform/darwin/src/MGLLight.h.ejs
+++ b/platform/darwin/src/MGLLight.h.ejs
@@ -33,7 +33,7 @@ typedef NS_ENUM(NSUInteger, MGLLight<%- camelize(property.name) %>) {
A structure containing information about the position of the light source
relative to lit geometries.
*/
-typedef struct MGLSphericalPosition {
+typedef struct __attribute__((objc_boxable)) MGLSphericalPosition {
/** Distance from the center of the base of an object to its light. */
CGFloat radial;
/** Position of the light relative to 0° (0° when `MGLLight.anchor` is set to viewport corresponds
@@ -77,7 +77,7 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-js/style-spec/#light-<%- originalPropertyName(property) %>"><code><%- originalPropertyName(property) %></code></a>
light property in the Mapbox Style Specification.
*/
-@property (nonatomic<% if (property.getter) { %>, getter=<%- objCGetter(property) -%><% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(property.name) %>;
+@property (nonatomic<% if (property.getter) { %>, getter=<%- objCGetter(property) -%><% } %>) NSExpression *<%- camelizeWithLeadingLowercase(property.name) %>;
<% if (property.transition) { -%>
/**
@@ -89,7 +89,7 @@ MGL_EXPORT
<% } -%>
<% if (property.original) { -%>
-@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> __attribute__((unavailable("Use <%- camelizeWithLeadingLowercase(property.name) %> instead.")));
+@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) NSExpression *<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> __attribute__((unavailable("Use <%- camelizeWithLeadingLowercase(property.name) %> instead.")));
<% } -%>
<% } -%>
diff --git a/platform/darwin/src/MGLLight.mm b/platform/darwin/src/MGLLight.mm
index c83ef127a6..db2893ed44 100644
--- a/platform/darwin/src/MGLLight.mm
+++ b/platform/darwin/src/MGLLight.mm
@@ -44,39 +44,39 @@ NS_INLINE mbgl::style::TransitionOptions MGLOptionsFromTransition(MGLTransition
{
if (self = [super init]) {
auto anchor = mbglLight->getAnchor();
- MGLStyleValue<NSValue *> *anchorStyleValue;
+ NSExpression *anchorExpression;
if (anchor.isUndefined()) {
mbgl::style::PropertyValue<mbgl::style::LightAnchorType> defaultAnchor = mbglLight->getDefaultAnchor();
- anchorStyleValue = MGLStyleValueTransformer<mbgl::style::LightAnchorType, NSValue *, mbgl::style::LightAnchorType, MGLLightAnchor>().toEnumStyleValue(defaultAnchor);
+ anchorExpression = MGLStyleValueTransformer<mbgl::style::LightAnchorType, NSValue *, mbgl::style::LightAnchorType, MGLLightAnchor>().toExpression(defaultAnchor);
} else {
- anchorStyleValue = MGLStyleValueTransformer<mbgl::style::LightAnchorType, NSValue *, mbgl::style::LightAnchorType, MGLLightAnchor>().toEnumStyleValue(anchor);
+ anchorExpression = MGLStyleValueTransformer<mbgl::style::LightAnchorType, NSValue *, mbgl::style::LightAnchorType, MGLLightAnchor>().toExpression(anchor);
}
- _anchor = anchorStyleValue;
+ _anchor = anchorExpression;
auto positionValue = mbglLight->getPosition();
if (positionValue.isUndefined()) {
- _position = MGLStyleValueTransformer<mbgl::style::Position, NSValue *>().toStyleValue(mbglLight->getDefaultPosition());
+ _position = MGLStyleValueTransformer<mbgl::style::Position, NSValue *>().toExpression(mbglLight->getDefaultPosition());
} else {
- _position = MGLStyleValueTransformer<mbgl::style::Position, NSValue *>().toStyleValue(positionValue);
+ _position = MGLStyleValueTransformer<mbgl::style::Position, NSValue *>().toExpression(positionValue);
}
_positionTransition = MGLTransitionFromOptions(mbglLight->getPositionTransition());
auto colorValue = mbglLight->getColor();
if (colorValue.isUndefined()) {
- _color = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(mbglLight->getDefaultColor());
+ _color = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(mbglLight->getDefaultColor());
} else {
- _color = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(colorValue);
+ _color = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(colorValue);
}
_colorTransition = MGLTransitionFromOptions(mbglLight->getColorTransition());
auto intensityValue = mbglLight->getIntensity();
if (intensityValue.isUndefined()) {
- _intensity = MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(mbglLight->getDefaultIntensity());
+ _intensity = MGLStyleValueTransformer<float, NSNumber *>().toExpression(mbglLight->getDefaultIntensity());
} else {
- _intensity = MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(intensityValue);
+ _intensity = MGLStyleValueTransformer<float, NSNumber *>().toExpression(intensityValue);
}
_intensityTransition = MGLTransitionFromOptions(mbglLight->getIntensityTransition());
@@ -89,20 +89,20 @@ NS_INLINE mbgl::style::TransitionOptions MGLOptionsFromTransition(MGLTransition
- (mbgl::style::Light)mbglLight
{
mbgl::style::Light mbglLight;
- auto anchor = MGLStyleValueTransformer<mbgl::style::LightAnchorType, NSValue *, mbgl::style::LightAnchorType, MGLLightAnchor>().toEnumPropertyValue(self.anchor);
+ auto anchor = MGLStyleValueTransformer<mbgl::style::LightAnchorType, NSValue *, mbgl::style::LightAnchorType, MGLLightAnchor>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::LightAnchorType>>(self.anchor);
mbglLight.setAnchor(anchor);
- auto position = MGLStyleValueTransformer<mbgl::style::Position, NSValue *>().toInterpolatablePropertyValue(self.position);
+ auto position = MGLStyleValueTransformer<mbgl::style::Position, NSValue *>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::Position>>(self.position);
mbglLight.setPosition(position);
mbglLight.setPositionTransition(MGLOptionsFromTransition(self.positionTransition));
- auto color = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toInterpolatablePropertyValue(self.color);
+ auto color = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::PropertyValue<mbgl::Color>>(self.color);
mbglLight.setColor(color);
mbglLight.setColorTransition(MGLOptionsFromTransition(self.colorTransition));
- auto intensity = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(self.intensity);
+ auto intensity = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(self.intensity);
mbglLight.setIntensity(intensity);
mbglLight.setIntensityTransition(MGLOptionsFromTransition(self.intensityTransition));
diff --git a/platform/darwin/src/MGLLight.mm.ejs b/platform/darwin/src/MGLLight.mm.ejs
index 0d0da124c8..b241269519 100644
--- a/platform/darwin/src/MGLLight.mm.ejs
+++ b/platform/darwin/src/MGLLight.mm.ejs
@@ -55,15 +55,15 @@ NS_INLINE mbgl::style::TransitionOptions MGLOptionsFromTransition(MGLTransition
<% for (const property of properties) { -%>
<% if (property.type == "enum") { -%>
auto <%- camelizeWithLeadingLowercase(property.name) -%> = mbglLight->get<%- camelize(property.name) -%>();
- MGLStyleValue<NSValue *> *<%- camelizeWithLeadingLowercase(property.name) -%>StyleValue;
+ NSExpression *<%- camelizeWithLeadingLowercase(property.name) -%>Expression;
if (<%- camelizeWithLeadingLowercase(property.name) -%>.isUndefined()) {
mbgl::style::PropertyValue<mbgl::style::Light<%- camelize(property.name) -%>Type> default<%- camelize(property.name) -%> = mbglLight->getDefault<%- camelize(property.name) -%>();
- <%- camelizeWithLeadingLowercase(property.name) -%>StyleValue = MGLStyleValueTransformer<mbgl::style::LightAnchorType, NSValue *, mbgl::style::Light<%- camelize(property.name) -%>Type, MGLLight<%- camelize(property.name) -%>>().toEnumStyleValue(default<%- camelize(property.name) -%>);
+ <%- camelizeWithLeadingLowercase(property.name) -%>Expression = MGLStyleValueTransformer<mbgl::style::LightAnchorType, NSValue *, mbgl::style::Light<%- camelize(property.name) -%>Type, MGLLight<%- camelize(property.name) -%>>().toExpression(default<%- camelize(property.name) -%>);
} else {
- <%- camelizeWithLeadingLowercase(property.name) -%>StyleValue = MGLStyleValueTransformer<mbgl::style::Light<%- camelize(property.name) -%>Type, NSValue *, mbgl::style::Light<%- camelize(property.name) -%>Type, MGLLight<%- camelize(property.name) -%>>().toEnumStyleValue(<%- camelizeWithLeadingLowercase(property.name) -%>);
+ <%- camelizeWithLeadingLowercase(property.name) -%>Expression = MGLStyleValueTransformer<mbgl::style::Light<%- camelize(property.name) -%>Type, NSValue *, mbgl::style::Light<%- camelize(property.name) -%>Type, MGLLight<%- camelize(property.name) -%>>().toExpression(<%- camelizeWithLeadingLowercase(property.name) -%>);
}
- _<%- camelizeWithLeadingLowercase(property.name) -%> = <%- camelizeWithLeadingLowercase(property.name) -%>StyleValue;
+ _<%- camelizeWithLeadingLowercase(property.name) -%> = <%- camelizeWithLeadingLowercase(property.name) -%>Expression;
<% if (property.transition) { -%>
_<%- camelizeWithLeadingLowercase(property.name) -%>Transition = MGLTransitionFromOptions(mbglLight->get<%- camelize(property.name) -%>Transition());
@@ -72,9 +72,9 @@ NS_INLINE mbgl::style::TransitionOptions MGLOptionsFromTransition(MGLTransition
<% } else {-%>
auto <%- camelizeWithLeadingLowercase(property.name) -%>Value = mbglLight->get<%- camelize(property.name) -%>();
if (<%- camelizeWithLeadingLowercase(property.name) -%>Value.isUndefined()) {
- _<%- camelizeWithLeadingLowercase(property.name) -%> = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(mbglLight->getDefault<%- camelize(property.name) -%>());
+ _<%- camelizeWithLeadingLowercase(property.name) -%> = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toExpression(mbglLight->getDefault<%- camelize(property.name) -%>());
} else {
- _<%- camelizeWithLeadingLowercase(property.name) -%> = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(<%- camelizeWithLeadingLowercase(property.name) -%>Value);
+ _<%- camelizeWithLeadingLowercase(property.name) -%> = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toExpression(<%- camelizeWithLeadingLowercase(property.name) -%>Value);
}
<% if (property.transition) { -%>
_<%- camelizeWithLeadingLowercase(property.name) -%>Transition = MGLTransitionFromOptions(mbglLight->get<%- camelize(property.name) -%>Transition());
@@ -93,11 +93,11 @@ NS_INLINE mbgl::style::TransitionOptions MGLOptionsFromTransition(MGLTransition
<% if (properties.length) { -%>
<% for (const property of properties) { -%>
<% if (property.type == "enum") { -%>
- auto <%- camelizeWithLeadingLowercase(property.name) -%> = MGLStyleValueTransformer<mbgl::style::Light<%- camelize(property.name) -%>Type, NSValue *, mbgl::style::Light<%- camelize(property.name) -%>Type, MGLLight<%- camelize(property.name) -%>>().toEnumPropertyValue(self.<%- camelizeWithLeadingLowercase(property.name) -%>);
+ auto <%- camelizeWithLeadingLowercase(property.name) -%> = MGLStyleValueTransformer<mbgl::style::Light<%- camelize(property.name) -%>Type, NSValue *, mbgl::style::Light<%- camelize(property.name) -%>Type, MGLLight<%- camelize(property.name) -%>>().toPropertyValue<mbgl::style::PropertyValue<<%- valueTransformerArguments(property)[0] %>>>(self.<%- camelizeWithLeadingLowercase(property.name) -%>);
mbglLight.set<%- camelize(property.name) -%>(<%- camelizeWithLeadingLowercase(property.name) -%>);
<% } else {-%>
- auto <%- camelizeWithLeadingLowercase(property.name) -%> = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toInterpolatablePropertyValue(self.<%- camelizeWithLeadingLowercase(property.name) -%>);
+ auto <%- camelizeWithLeadingLowercase(property.name) -%> = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue<mbgl::style::PropertyValue<<%- valueTransformerArguments(property)[0] %>>>(self.<%- camelizeWithLeadingLowercase(property.name) -%>);
mbglLight.set<%- camelize(property.name) -%>(<%- camelizeWithLeadingLowercase(property.name) -%>);
<% } -%>
diff --git a/platform/darwin/src/MGLLineStyleLayer.h b/platform/darwin/src/MGLLineStyleLayer.h
index 46025ddbf0..32c8ece6c5 100644
--- a/platform/darwin/src/MGLLineStyleLayer.h
+++ b/platform/darwin/src/MGLLineStyleLayer.h
@@ -2,7 +2,6 @@
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLFoundation.h"
-#import "MGLStyleValue.h"
#import "MGLVectorStyleLayer.h"
NS_ASSUME_NONNULL_BEGIN
@@ -58,7 +57,7 @@ typedef NS_ENUM(NSUInteger, MGLLineJoin) {
};
/**
- Controls the translation reference point.
+ Controls the frame of reference for `MGLLineStyleLayer.lineTranslation`.
Values of this type are used in the `MGLLineStyleLayer.lineTranslationAnchor`
property.
@@ -79,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;
@@ -94,12 +94,11 @@ typedef NS_ENUM(NSUInteger, MGLLineTranslationAnchor) {
```swift
let layer = MGLLineStyleLayer(identifier: "trails-path", source: trails)
layer.sourceLayerIdentifier = "trails"
- layer.lineWidth = MGLStyleValue(interpolationMode: .exponential,
- cameraStops: [14: MGLStyleValue(rawValue: 2),
- 18: MGLStyleValue(rawValue: 20)],
- options: [.interpolationBase: 1.5])
- layer.lineColor = MGLStyleValue(rawValue: .brown)
- layer.lineCap = MGLStyleValue(rawValue: NSValue(mglLineCap: .round))
+ layer.lineWidth = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'exponential', 1.5, %@)",
+ [14: 2,
+ 18: 20])
+ layer.lineColor = NSExpression(forConstantValue: UIColor.brown)
+ layer.lineCap = NSExpression(forConstantValue: "round")
layer.predicate = NSPredicate(format: "%K == %@", "trail-type", "mountain-biking")
mapView.style?.addLayer(layer)
```
@@ -127,82 +126,99 @@ MGL_EXPORT
/**
The display of line endings.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLLineCapButt`. Set this property to `nil` to
- reset it to the default value.
-
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ The default value of this property is an expression that evaluates to `butt`.
+ 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 `MGLLineCap` values
+ * Any of the following constant string values:
+ * `butt`: A cap with a squared-off end which is drawn to the exact endpoint
+ of the line.
+ * `round`: A cap with a rounded end which is drawn beyond the endpoint of the
+ line at a radius of one-half of the line's width and centered on the endpoint
+ of the line.
+ * `square`: A cap with a squared-off end which is drawn beyond the endpoint
+ of the line at a distance of one-half of the line's width.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
+
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineCap;
+@property (nonatomic, null_resettable) NSExpression *lineCap;
/**
The display of lines when joining.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLLineJoinMiter`. Set this property to `nil` to
- reset it to the default value.
-
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ The default value of this property is an expression that evaluates to `miter`.
+ 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 `MGLLineJoin` values
+ * Any of the following constant string values:
+ * `bevel`: A join with a squared-off end which is drawn beyond the endpoint
+ of the line at a distance of one-half of the line's width.
+ * `round`: A join with a rounded end which is drawn beyond the endpoint of
+ the line at a radius of one-half of the line's width and centered on the
+ endpoint of the line.
+ * `miter`: A join with a sharp, angled corner which is drawn with the outer
+ sides beyond the endpoint of the path until they meet.
+ * 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) MGLStyleValue<NSValue *> *lineJoin;
+@property (nonatomic, null_resettable) NSExpression *lineJoin;
/**
Used to automatically convert miter joins to bevel joins for sharp angles.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `2`. Set this property to `nil` to reset
- it to the default value.
+ 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.
This property is only applied to the style if `lineJoin` is set to an
- `MGLStyleValue` object containing an `NSValue` object containing
- `MGLLineJoinMiter`. Otherwise, it is ignored.
+ expression that evaluates to `miter`. Otherwise, it is ignored.
+
+ You can set this property to an expression containing any of the following:
- You can set this property to an instance of:
+ * Constant numeric 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineMiterLimit;
+@property (nonatomic, null_resettable) NSExpression *lineMiterLimit;
/**
Used to automatically convert round joins to miter joins for shallow angles.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `1.05`. Set this property to `nil` to
- reset it to the default value.
+ 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.
This property is only applied to the style if `lineJoin` is set to an
- `MGLStyleValue` object containing an `NSValue` object containing
- `MGLLineJoinRound`. Otherwise, it is ignored.
+ expression that evaluates to `round`. Otherwise, it is ignored.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ * Constant numeric 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) MGLStyleValue<NSNumber *> *lineRoundLimit;
+@property (nonatomic, null_resettable) NSExpression *lineRoundLimit;
#pragma mark - Accessing the Paint Attributes
@@ -211,27 +227,19 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
-
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values no less than 0
+ * 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) MGLStyleValue<NSNumber *> *lineBlur;
+@property (nonatomic, null_resettable) NSExpression *lineBlur;
/**
The transition affecting any changes to this layer’s `lineBlur` property.
@@ -244,58 +252,44 @@ MGL_EXPORT
/**
The color with which the line will be drawn.
- The default value of this property is an `MGLStyleValue` object containing
+ The default value of this property is an expression that evaluates to
`UIColor.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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ You can set this property to an expression containing any of the following:
+
+ * Constant `UIColor` 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) MGLStyleValue<UIColor *> *lineColor;
+@property (nonatomic, null_resettable) NSExpression *lineColor;
#else
/**
The color with which the line will be drawn.
- The default value of this property is an `MGLStyleValue` object containing
+ 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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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) MGLStyleValue<NSColor *> *lineColor;
+@property (nonatomic, null_resettable) NSExpression *lineColor;
#endif
/**
@@ -308,7 +302,10 @@ MGL_EXPORT
/**
Specifies the lengths of the alternating dashes and gaps that form the dash
pattern. The lengths are later scaled by the line width. To convert a dash
- length to points, multiply the length by the current line width.
+ length to points, multiply the length by the current line width. Note that
+ GeoJSON sources with `lineMetrics: true` specified won't render dashed lines to
+ the expected scale. Also note that zoom-dependent expressions will be evaluated
+ only at integer zoom levels.
This property is measured in line widths.
@@ -319,13 +316,19 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-dasharray"><code>line-dasharray</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant array values no less than 0
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSNumber *> *> *lineDashPattern;
+@property (nonatomic, null_resettable) NSExpression *lineDashPattern;
/**
The transition affecting any changes to this layer’s `lineDashPattern` property.
@@ -334,7 +337,7 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition lineDashPatternTransition;
-@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSNumber *> *> *lineDasharray __attribute__((unavailable("Use lineDashPattern instead.")));
+@property (nonatomic, null_resettable) NSExpression *lineDasharray __attribute__((unavailable("Use lineDashPattern instead.")));
/**
Draws a line casing outside of a line's actual path. Value indicates the width
@@ -342,27 +345,19 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
-
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values no less than 0
+ * 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) MGLStyleValue<NSNumber *> *lineGapWidth;
+@property (nonatomic, null_resettable) NSExpression *lineGapWidth;
/**
The transition affecting any changes to this layer’s `lineGapWidth` property.
@@ -379,27 +374,19 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
-
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric 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) MGLStyleValue<NSNumber *> *lineOffset;
+@property (nonatomic, null_resettable) NSExpression *lineOffset;
/**
The transition affecting any changes to this layer’s `lineOffset` property.
@@ -411,27 +398,19 @@ MGL_EXPORT
/**
The opacity at which the line will be drawn.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `1`. Set this property to `nil` to reset
- it to the default value.
-
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values between 0 and 1 inclusive
+ * 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) MGLStyleValue<NSNumber *> *lineOpacity;
+@property (nonatomic, null_resettable) NSExpression *lineOpacity;
/**
The transition affecting any changes to this layer’s `lineOpacity` property.
@@ -444,13 +423,19 @@ MGL_EXPORT
Name of image in style images to use for drawing image lines. For seamless
patterns, image width must be a factor of two (2, 4, 8, ..., 512).
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant string values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *linePattern;
+@property (nonatomic, null_resettable) NSExpression *linePattern;
/**
The transition affecting any changes to this layer’s `linePattern` property.
@@ -465,7 +450,7 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points downward. Set this property to `nil` to reset it to the default value.
@@ -473,21 +458,25 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-translate"><code>line-translate</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ * Constant `CGVector` 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) MGLStyleValue<NSValue *> *lineTranslation;
+@property (nonatomic, null_resettable) NSExpression *lineTranslation;
#else
/**
The geometry's offset.
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points upward. Set this property to `nil` to reset it to the default value.
@@ -495,14 +484,18 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-translate"><code>line-translate</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant `CGVector` 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslation;
+@property (nonatomic, null_resettable) NSExpression *lineTranslation;
#endif
/**
@@ -512,14 +505,13 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition lineTranslationTransition;
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslate __attribute__((unavailable("Use lineTranslation instead.")));
+@property (nonatomic, null_resettable) NSExpression *lineTranslate __attribute__((unavailable("Use lineTranslation instead.")));
/**
- Controls the translation reference point.
+ Controls the frame of reference for `lineTranslation`.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLLineTranslationAnchorMap`. Set this property to
- `nil` to reset it to the default value.
+ The default value of this property is an expression that evaluates to `map`.
+ Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `lineTranslation` is non-`nil`.
Otherwise, it is ignored.
@@ -528,42 +520,43 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-translate-anchor"><code>line-translate-anchor</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant `MGLLineTranslationAnchor` values
+ * Any of the following constant string values:
+ * `map`: The line is translated relative to the map.
+ * `viewport`: The line is translated relative to the viewport.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslationAnchor;
+@property (nonatomic, null_resettable) NSExpression *lineTranslationAnchor;
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslateAnchor __attribute__((unavailable("Use lineTranslationAnchor instead.")));
+@property (nonatomic, null_resettable) NSExpression *lineTranslateAnchor __attribute__((unavailable("Use lineTranslationAnchor instead.")));
/**
Stroke thickness.
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `1`. Set this property to `nil` to reset
- it to the default value.
-
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ 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.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values no less than 0
+ * 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) MGLStyleValue<NSNumber *> *lineWidth;
+@property (nonatomic, null_resettable) NSExpression *lineWidth;
/**
The transition affecting any changes to this layer’s `lineWidth` property.
diff --git a/platform/darwin/src/MGLLineStyleLayer.mm b/platform/darwin/src/MGLLineStyleLayer.mm
index 5b2652cdeb..619cc70afe 100644
--- a/platform/darwin/src/MGLLineStyleLayer.mm
+++ b/platform/darwin/src/MGLLineStyleLayer.mm
@@ -89,91 +89,91 @@ namespace mbgl {
#pragma mark - Accessing the Layout Attributes
-- (void)setLineCap:(MGLStyleValue<NSValue *> *)lineCap {
+- (void)setLineCap:(NSExpression *)lineCap {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::LineCapType, NSValue *, mbgl::style::LineCapType, MGLLineCap>().toEnumPropertyValue(lineCap);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::LineCapType, NSValue *, mbgl::style::LineCapType, MGLLineCap>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::LineCapType>>(lineCap);
self.rawLayer->setLineCap(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)lineCap {
+- (NSExpression *)lineCap {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineCap();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::LineCapType, NSValue *, mbgl::style::LineCapType, MGLLineCap>().toEnumStyleValue(self.rawLayer->getDefaultLineCap());
+ propertyValue = self.rawLayer->getDefaultLineCap();
}
- return MGLStyleValueTransformer<mbgl::style::LineCapType, NSValue *, mbgl::style::LineCapType, MGLLineCap>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::LineCapType, NSValue *, mbgl::style::LineCapType, MGLLineCap>().toExpression(propertyValue);
}
-- (void)setLineJoin:(MGLStyleValue<NSValue *> *)lineJoin {
+- (void)setLineJoin:(NSExpression *)lineJoin {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toDataDrivenPropertyValue(lineJoin);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<mbgl::style::LineJoinType>>(lineJoin);
self.rawLayer->setLineJoin(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)lineJoin {
+- (NSExpression *)lineJoin {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineJoin();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toDataDrivenStyleValue(self.rawLayer->getDefaultLineJoin());
+ propertyValue = self.rawLayer->getDefaultLineJoin();
}
- return MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toExpression(propertyValue);
}
-- (void)setLineMiterLimit:(MGLStyleValue<NSNumber *> *)lineMiterLimit {
+- (void)setLineMiterLimit:(NSExpression *)lineMiterLimit {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(lineMiterLimit);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(lineMiterLimit);
self.rawLayer->setLineMiterLimit(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)lineMiterLimit {
+- (NSExpression *)lineMiterLimit {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineMiterLimit();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultLineMiterLimit());
+ propertyValue = self.rawLayer->getDefaultLineMiterLimit();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
-- (void)setLineRoundLimit:(MGLStyleValue<NSNumber *> *)lineRoundLimit {
+- (void)setLineRoundLimit:(NSExpression *)lineRoundLimit {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(lineRoundLimit);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(lineRoundLimit);
self.rawLayer->setLineRoundLimit(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)lineRoundLimit {
+- (NSExpression *)lineRoundLimit {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineRoundLimit();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultLineRoundLimit());
+ propertyValue = self.rawLayer->getDefaultLineRoundLimit();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
#pragma mark - Accessing the Paint Attributes
-- (void)setLineBlur:(MGLStyleValue<NSNumber *> *)lineBlur {
+- (void)setLineBlur:(NSExpression *)lineBlur {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(lineBlur);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(lineBlur);
self.rawLayer->setLineBlur(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)lineBlur {
+- (NSExpression *)lineBlur {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineBlur();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultLineBlur());
+ propertyValue = self.rawLayer->getDefaultLineBlur();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setLineBlurTransition:(MGLTransition )transition {
@@ -194,21 +194,21 @@ namespace mbgl {
return transition;
}
-- (void)setLineColor:(MGLStyleValue<MGLColor *> *)lineColor {
+- (void)setLineColor:(NSExpression *)lineColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(lineColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<mbgl::Color>>(lineColor);
self.rawLayer->setLineColor(mbglValue);
}
-- (MGLStyleValue<MGLColor *> *)lineColor {
+- (NSExpression *)lineColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineColor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultLineColor());
+ propertyValue = self.rawLayer->getDefaultLineColor();
}
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(propertyValue);
}
- (void)setLineColorTransition:(MGLTransition )transition {
@@ -229,21 +229,21 @@ namespace mbgl {
return transition;
}
-- (void)setLineDashPattern:(MGLStyleValue<NSArray<NSNumber *> *> *)lineDashPattern {
+- (void)setLineDashPattern:(NSExpression *)lineDashPattern {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::vector<float>, NSArray<NSNumber *> *, float>().toPropertyValue(lineDashPattern);
+ auto mbglValue = MGLStyleValueTransformer<std::vector<float>, NSArray<NSNumber *> *, float>().toPropertyValue<mbgl::style::PropertyValue<std::vector<float>>>(lineDashPattern);
self.rawLayer->setLineDasharray(mbglValue);
}
-- (MGLStyleValue<NSArray<NSNumber *> *> *)lineDashPattern {
+- (NSExpression *)lineDashPattern {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineDasharray();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::vector<float>, NSArray<NSNumber *> *, float>().toStyleValue(self.rawLayer->getDefaultLineDasharray());
+ propertyValue = self.rawLayer->getDefaultLineDasharray();
}
- return MGLStyleValueTransformer<std::vector<float>, NSArray<NSNumber *> *, float>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<std::vector<float>, NSArray<NSNumber *> *, float>().toExpression(propertyValue);
}
- (void)setLineDashPatternTransition:(MGLTransition )transition {
@@ -264,28 +264,28 @@ namespace mbgl {
return transition;
}
-- (void)setLineDasharray:(MGLStyleValue<NSArray<NSNumber *> *> *)lineDasharray {
+- (void)setLineDasharray:(NSExpression *)lineDasharray {
}
-- (MGLStyleValue<NSArray<NSNumber *> *> *)lineDasharray {
+- (NSExpression *)lineDasharray {
return self.lineDashPattern;
}
-- (void)setLineGapWidth:(MGLStyleValue<NSNumber *> *)lineGapWidth {
+- (void)setLineGapWidth:(NSExpression *)lineGapWidth {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(lineGapWidth);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(lineGapWidth);
self.rawLayer->setLineGapWidth(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)lineGapWidth {
+- (NSExpression *)lineGapWidth {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineGapWidth();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultLineGapWidth());
+ propertyValue = self.rawLayer->getDefaultLineGapWidth();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setLineGapWidthTransition:(MGLTransition )transition {
@@ -306,21 +306,21 @@ namespace mbgl {
return transition;
}
-- (void)setLineOffset:(MGLStyleValue<NSNumber *> *)lineOffset {
+- (void)setLineOffset:(NSExpression *)lineOffset {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(lineOffset);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(lineOffset);
self.rawLayer->setLineOffset(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)lineOffset {
+- (NSExpression *)lineOffset {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineOffset();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultLineOffset());
+ propertyValue = self.rawLayer->getDefaultLineOffset();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setLineOffsetTransition:(MGLTransition )transition {
@@ -341,21 +341,21 @@ namespace mbgl {
return transition;
}
-- (void)setLineOpacity:(MGLStyleValue<NSNumber *> *)lineOpacity {
+- (void)setLineOpacity:(NSExpression *)lineOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(lineOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(lineOpacity);
self.rawLayer->setLineOpacity(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)lineOpacity {
+- (NSExpression *)lineOpacity {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineOpacity();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultLineOpacity());
+ propertyValue = self.rawLayer->getDefaultLineOpacity();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setLineOpacityTransition:(MGLTransition )transition {
@@ -376,21 +376,22 @@ namespace mbgl {
return transition;
}
-- (void)setLinePattern:(MGLStyleValue<NSString *> *)linePattern {
+- (void)setLinePattern:(NSExpression *)linePattern {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(linePattern);
+ auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue<mbgl::style::PropertyValue<std::string>>(linePattern);
self.rawLayer->setLinePattern(mbglValue);
}
-- (MGLStyleValue<NSString *> *)linePattern {
+- (NSExpression *)linePattern {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLinePattern();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(self.rawLayer->getDefaultLinePattern());
+ propertyValue = self.rawLayer->getDefaultLinePattern();
}
- return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
+ NSExpression *expression = MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ return expression.mgl_expressionByReplacingTokensWithKeyPaths;
}
- (void)setLinePatternTransition:(MGLTransition )transition {
@@ -411,21 +412,21 @@ namespace mbgl {
return transition;
}
-- (void)setLineTranslation:(MGLStyleValue<NSValue *> *)lineTranslation {
+- (void)setLineTranslation:(NSExpression *)lineTranslation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toInterpolatablePropertyValue(lineTranslation);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue<mbgl::style::PropertyValue<std::array<float, 2>>>(lineTranslation);
self.rawLayer->setLineTranslate(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)lineTranslation {
+- (NSExpression *)lineTranslation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineTranslate();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(self.rawLayer->getDefaultLineTranslate());
+ propertyValue = self.rawLayer->getDefaultLineTranslate();
}
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toExpression(propertyValue);
}
- (void)setLineTranslationTransition:(MGLTransition )transition {
@@ -446,52 +447,52 @@ namespace mbgl {
return transition;
}
-- (void)setLineTranslate:(MGLStyleValue<NSValue *> *)lineTranslate {
+- (void)setLineTranslate:(NSExpression *)lineTranslate {
}
-- (MGLStyleValue<NSValue *> *)lineTranslate {
+- (NSExpression *)lineTranslate {
return self.lineTranslation;
}
-- (void)setLineTranslationAnchor:(MGLStyleValue<NSValue *> *)lineTranslationAnchor {
+- (void)setLineTranslationAnchor:(NSExpression *)lineTranslationAnchor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslationAnchor>().toEnumPropertyValue(lineTranslationAnchor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslationAnchor>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType>>(lineTranslationAnchor);
self.rawLayer->setLineTranslateAnchor(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)lineTranslationAnchor {
+- (NSExpression *)lineTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineTranslateAnchor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslationAnchor>().toEnumStyleValue(self.rawLayer->getDefaultLineTranslateAnchor());
+ propertyValue = self.rawLayer->getDefaultLineTranslateAnchor();
}
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslationAnchor>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslationAnchor>().toExpression(propertyValue);
}
-- (void)setLineTranslateAnchor:(MGLStyleValue<NSValue *> *)lineTranslateAnchor {
+- (void)setLineTranslateAnchor:(NSExpression *)lineTranslateAnchor {
}
-- (MGLStyleValue<NSValue *> *)lineTranslateAnchor {
+- (NSExpression *)lineTranslateAnchor {
return self.lineTranslationAnchor;
}
-- (void)setLineWidth:(MGLStyleValue<NSNumber *> *)lineWidth {
+- (void)setLineWidth:(NSExpression *)lineWidth {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(lineWidth);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(lineWidth);
self.rawLayer->setLineWidth(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)lineWidth {
+- (NSExpression *)lineWidth {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getLineWidth();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultLineWidth());
+ propertyValue = self.rawLayer->getDefaultLineWidth();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setLineWidthTransition:(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/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm
index db236a8aeb..19fa0223a4 100644
--- a/platform/darwin/src/MGLMapSnapshotter.mm
+++ b/platform/darwin/src/MGLMapSnapshotter.mm
@@ -89,7 +89,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
std::shared_ptr<mbgl::ThreadPool> _mbglThreadPool;
std::unique_ptr<mbgl::MapSnapshotter> _mbglMapSnapshotter;
std::unique_ptr<mbgl::Actor<mbgl::MapSnapshotter::Callback>> _snapshotCallback;
- NS_ARRAY_OF(MGLAttributionInfo *) *_attributionInfo;
+ NSArray<MGLAttributionInfo *> *_attributionInfo;
}
@@ -343,6 +343,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
#else
image = [[NSImage alloc] initWithCGImage:cgimg size:[backgroundImage extent].size];
#endif
+
CGImageRelease(cgimg);
return image;
}
diff --git a/platform/darwin/src/MGLMultiPoint.mm b/platform/darwin/src/MGLMultiPoint.mm
index 240dad9614..5a7262b0a4 100644
--- a/platform/darwin/src/MGLMultiPoint.mm
+++ b/platform/darwin/src/MGLMultiPoint.mm
@@ -70,7 +70,7 @@
return _coordinates.size();
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingPointCount
++ (NSSet<NSString *> *)keyPathsForValuesAffectingPointCount
{
return [NSSet setWithObjects:@"coordinates", nil];
}
diff --git a/platform/darwin/src/MGLNetworkConfiguration.h b/platform/darwin/src/MGLNetworkConfiguration.h
index f1fe7bab2c..2db46d78c5 100644
--- a/platform/darwin/src/MGLNetworkConfiguration.h
+++ b/platform/darwin/src/MGLNetworkConfiguration.h
@@ -2,12 +2,6 @@
NS_ASSUME_NONNULL_BEGIN
-/// The default base URL for Mapbox APIs other than the telemetry API.
-extern NSString * const MGLDefaultMapboxAPIBaseURL;
-
-/// The PRC base URL for Mapbox APIs other than the telemetry API.
-extern NSString * const MGLChinaMapboxAPIBaseURL;
-
/**
The MGLNetworkConfiguration object provides a global way to set a base API URL for
retrieval of map data, styles, and other resources.
@@ -19,7 +13,7 @@ extern NSString * const MGLChinaMapboxAPIBaseURL;
@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/MGLNetworkConfiguration.m b/platform/darwin/src/MGLNetworkConfiguration.m
index d0ee01c5a2..4cfa405a1a 100644
--- a/platform/darwin/src/MGLNetworkConfiguration.m
+++ b/platform/darwin/src/MGLNetworkConfiguration.m
@@ -1,8 +1,5 @@
#import "MGLNetworkConfiguration.h"
-NSString * const MGLDefaultMapboxAPIBaseURL = @"https://api.mapbox.com";
-NSString * const MGLChinaMapboxAPIBaseURL = @"https://api.mapbox.cn";
-
@implementation MGLNetworkConfiguration
+ (void)load {
@@ -16,7 +13,7 @@ NSString * const MGLChinaMapboxAPIBaseURL = @"https://api.mapbox.cn";
+ (instancetype)sharedManager {
static dispatch_once_t onceToken;
static MGLNetworkConfiguration *_sharedManager;
- void (^setupBlock)() = ^{
+ void (^setupBlock)(void) = ^{
dispatch_once(&onceToken, ^{
_sharedManager = [[self alloc] init];
});
diff --git a/platform/darwin/src/MGLOfflineStorage.h b/platform/darwin/src/MGLOfflineStorage.h
index b009f893b3..ab36592634 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
@@ -199,7 +199,7 @@ MGL_EXPORT
`packs` property, observe KVO change notifications on the `packs` key path.
The initial load results in an `NSKeyValueChangeSetting` change.
*/
-@property (nonatomic, strong, readonly, nullable) NS_ARRAY_OF(MGLOfflinePack *) *packs;
+@property (nonatomic, strong, readonly, nullable) NSArray<MGLOfflinePack *> *packs;
/**
Creates and registers an offline pack that downloads the resources needed to
diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm
index 7085aa58e5..f4e454534d 100644
--- a/platform/darwin/src/MGLOfflineStorage.mm
+++ b/platform/darwin/src/MGLOfflineStorage.mm
@@ -26,17 +26,13 @@ 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 ()
-@property (nonatomic, strong, readwrite) NS_MUTABLE_ARRAY_OF(MGLOfflinePack *) *packs;
+@property (nonatomic, strong, readwrite) NSMutableArray<MGLOfflinePack *> *packs;
@property (nonatomic) mbgl::DefaultFileSource *mbglFileSource;
@property (nonatomic, getter=isPaused) BOOL paused;
@@ -247,7 +243,7 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
_mbglFileSource = nullptr;
}
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NS_DICTIONARY_OF(NSString *, id) *)change context:(void *)context {
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *, id> *)change context:(void *)context {
// Synchronize the file source’s access token with the global one in MGLAccountManager.
if ([keyPath isEqualToString:@"accessToken"] && object == [MGLAccountManager sharedManager]) {
NSString *accessToken = change[NSKeyValueChangeNewKey];
@@ -340,7 +336,7 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
}
- (void)reloadPacks {
- [self getPacksWithCompletionHandler:^(NS_ARRAY_OF(MGLOfflinePack *) *packs, __unused NSError * _Nullable error) {
+ [self getPacksWithCompletionHandler:^(NSArray<MGLOfflinePack *> *packs, __unused NSError * _Nullable error) {
for (MGLOfflinePack *pack in self.packs) {
[pack invalidate];
}
@@ -348,7 +344,7 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
}];
}
-- (void)getPacksWithCompletionHandler:(void (^)(NS_ARRAY_OF(MGLOfflinePack *) *packs, NSError * _Nullable error))completion {
+- (void)getPacksWithCompletionHandler:(void (^)(NSArray<MGLOfflinePack *> *packs, NSError * _Nullable error))completion {
self.mbglFileSource->listOfflineRegions([&, completion](std::exception_ptr exception, mbgl::optional<std::vector<mbgl::OfflineRegion>> regions) {
NSError *error;
if (exception) {
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+MGLAdditions.h b/platform/darwin/src/MGLPolygon+MGLAdditions.h
deleted file mode 100644
index f409fb96ca..0000000000
--- a/platform/darwin/src/MGLPolygon+MGLAdditions.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#import <Mapbox/Mapbox.h>
-
-@interface MGLPolygon (MGLAdditions)
-
-- (NS_ARRAY_OF(id) *)mgl_coordinates;
-
-@end
diff --git a/platform/darwin/src/MGLPolygon+MGLAdditions.m b/platform/darwin/src/MGLPolygon+MGLAdditions.m
deleted file mode 100644
index 3e76a37157..0000000000
--- a/platform/darwin/src/MGLPolygon+MGLAdditions.m
+++ /dev/null
@@ -1,27 +0,0 @@
-#import "MGLPolygon+MGLAdditions.h"
-
-@implementation MGLPolygon (MGLAdditions)
-
-- (NS_ARRAY_OF(id) *)mgl_coordinates {
- NSMutableArray *coordinates = [NSMutableArray array];
-
- NSMutableArray *exteriorRing = [NSMutableArray array];
- for (NSUInteger index = 0; index < self.pointCount; index++) {
- CLLocationCoordinate2D coordinate = self.coordinates[index];
- [exteriorRing addObject:@[@(coordinate.longitude), @(coordinate.latitude)]];
- }
- [coordinates addObject:exteriorRing];
-
- for (MGLPolygon *interiorPolygon in self.interiorPolygons) {
- NSMutableArray *interiorRing = [NSMutableArray array];
- for (int index = 0; index < interiorPolygon.pointCount; index++) {
- CLLocationCoordinate2D coordinate = interiorPolygon.coordinates[index];
- [interiorRing addObject:@[@(coordinate.longitude), @(coordinate.latitude)]];
- }
- [coordinates addObject:interiorRing];
- }
-
- return [coordinates copy];
-}
-
-@end
diff --git a/platform/darwin/src/MGLPolygon.h b/platform/darwin/src/MGLPolygon.h
index 3fcc1be76d..810a8b78ae 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
@@ -56,7 +57,7 @@ MGL_EXPORT
If there are no interior polygons, the value of this property is `nil`.
*/
-@property (nonatomic, nullable, readonly) NS_ARRAY_OF(MGLPolygon *) *interiorPolygons;
+@property (nonatomic, nullable, readonly) NSArray<MGLPolygon *> *interiorPolygons;
/**
Creates and returns an `MGLPolygon` object from the specified set of
@@ -81,7 +82,7 @@ MGL_EXPORT
is considered to have no interior polygons.
@return A new polygon object.
*/
-+ (instancetype)polygonWithCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count interiorPolygons:(nullable NS_ARRAY_OF(MGLPolygon *) *)interiorPolygons;
++ (instancetype)polygonWithCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count interiorPolygons:(nullable NSArray<MGLPolygon *> *)interiorPolygons;
@end
@@ -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
@@ -108,7 +109,7 @@ MGL_EXPORT
/**
An array of polygons forming the multipolygon.
*/
-@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLPolygon *) *polygons;
+@property (nonatomic, copy, readonly) NSArray<MGLPolygon *> *polygons;
/**
Creates and returns a multipolygon object consisting of the given polygons.
@@ -116,7 +117,7 @@ MGL_EXPORT
@param polygons The array of polygons defining the shape.
@return A new multipolygon object.
*/
-+ (instancetype)multiPolygonWithPolygons:(NS_ARRAY_OF(MGLPolygon *) *)polygons;
++ (instancetype)multiPolygonWithPolygons:(NSArray<MGLPolygon *> *)polygons;
@end
diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm
index e7843224e9..b80504707b 100644
--- a/platform/darwin/src/MGLPolygon.mm
+++ b/platform/darwin/src/MGLPolygon.mm
@@ -1,9 +1,9 @@
-#import "MGLPolygon.h"
+#import "MGLPolygon_Private.h"
#import "MGLMultiPoint_Private.h"
#import "MGLGeometry_Private.h"
-#import "MGLPolygon+MGLAdditions.h"
+#import "MGLFeature.h"
#import <mbgl/util/geojson.hpp>
#import <mapbox/polylabel.hpp>
@@ -102,11 +102,33 @@
@"coordinates": self.mgl_coordinates};
}
+- (NSArray<id> *)mgl_coordinates {
+ NSMutableArray *coordinates = [NSMutableArray array];
+
+ NSMutableArray *exteriorRing = [NSMutableArray array];
+ for (NSUInteger index = 0; index < self.pointCount; index++) {
+ CLLocationCoordinate2D coordinate = self.coordinates[index];
+ [exteriorRing addObject:@[@(coordinate.longitude), @(coordinate.latitude)]];
+ }
+ [coordinates addObject:exteriorRing];
+
+ for (MGLPolygon *interiorPolygon in self.interiorPolygons) {
+ NSMutableArray *interiorRing = [NSMutableArray array];
+ for (int index = 0; index < interiorPolygon.pointCount; index++) {
+ CLLocationCoordinate2D coordinate = interiorPolygon.coordinates[index];
+ [interiorRing addObject:@[@(coordinate.longitude), @(coordinate.latitude)]];
+ }
+ [coordinates addObject:interiorRing];
+ }
+
+ return [coordinates copy];
+}
+
@end
@interface MGLMultiPolygon ()
-@property (nonatomic, copy, readwrite) NS_ARRAY_OF(MGLPolygon *) *polygons;
+@property (nonatomic, copy, readwrite) NSArray<MGLPolygon *> *polygons;
@end
@@ -116,11 +138,11 @@
@synthesize overlayBounds = _overlayBounds;
-+ (instancetype)multiPolygonWithPolygons:(NS_ARRAY_OF(MGLPolygon *) *)polygons {
++ (instancetype)multiPolygonWithPolygons:(NSArray<MGLPolygon *> *)polygons {
return [[self alloc] initWithPolygons:polygons];
}
-- (instancetype)initWithPolygons:(NS_ARRAY_OF(MGLPolygon *) *)polygons {
+- (instancetype)initWithPolygons:(NSArray<MGLPolygon *> *)polygons {
if (self = [super init]) {
_polygons = polygons;
diff --git a/platform/darwin/src/MGLPolygon_Private.h b/platform/darwin/src/MGLPolygon_Private.h
new file mode 100644
index 0000000000..b006f2d77f
--- /dev/null
+++ b/platform/darwin/src/MGLPolygon_Private.h
@@ -0,0 +1,11 @@
+#import "MGLPolygon.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MGLPolygon (Private)
+
+- (NSArray<id> *)mgl_coordinates;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLPolyline+MGLAdditions.h b/platform/darwin/src/MGLPolyline+MGLAdditions.h
deleted file mode 100644
index 4cdbbf17f9..0000000000
--- a/platform/darwin/src/MGLPolyline+MGLAdditions.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#import <Mapbox/Mapbox.h>
-
-@interface MGLPolyline (MGLAdditions)
-
-- (NS_ARRAY_OF(id) *)mgl_coordinates;
-
-@end
diff --git a/platform/darwin/src/MGLPolyline+MGLAdditions.m b/platform/darwin/src/MGLPolyline+MGLAdditions.m
deleted file mode 100644
index d1db2c58a0..0000000000
--- a/platform/darwin/src/MGLPolyline+MGLAdditions.m
+++ /dev/null
@@ -1,14 +0,0 @@
-#import "MGLPolyline+MGLAdditions.h"
-
-@implementation MGLPolyline (MGLAdditions)
-
-- (NS_ARRAY_OF(id) *)mgl_coordinates {
- NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:self.pointCount];
- for (NSUInteger index = 0; index < self.pointCount; index++) {
- CLLocationCoordinate2D coordinate = self.coordinates[index];
- [coordinates addObject:@[@(coordinate.longitude), @(coordinate.latitude)]];
- }
- return [coordinates copy];
-}
-
-@end
diff --git a/platform/darwin/src/MGLPolyline.h b/platform/darwin/src/MGLPolyline.h
index e46baa91cc..8e9007686b 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
@@ -91,7 +92,7 @@ MGL_EXPORT
/**
An array of polygons forming the multipolyline.
*/
-@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLPolyline *) *polylines;
+@property (nonatomic, copy, readonly) NSArray<MGLPolyline *> *polylines;
/**
Creates and returns a multipolyline object consisting of the given polylines.
@@ -99,7 +100,7 @@ MGL_EXPORT
@param polylines The array of polylines defining the shape.
@return A new multipolyline object.
*/
-+ (instancetype)multiPolylineWithPolylines:(NS_ARRAY_OF(MGLPolyline *) *)polylines;
++ (instancetype)multiPolylineWithPolylines:(NSArray<MGLPolyline *> *)polylines;
@end
diff --git a/platform/darwin/src/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm
index 0e371a4dda..a028db8176 100644
--- a/platform/darwin/src/MGLPolyline.mm
+++ b/platform/darwin/src/MGLPolyline.mm
@@ -1,9 +1,9 @@
-#import "MGLPolyline.h"
+#import "MGLPolyline_Private.h"
#import "MGLMultiPoint_Private.h"
#import "MGLGeometry_Private.h"
-#import "MGLPolyline+MGLAdditions.h"
+#import "MGLFeature.h"
#import <mbgl/util/geojson.hpp>
#import <mapbox/polylabel.hpp>
@@ -49,6 +49,15 @@
@"coordinates": self.mgl_coordinates};
}
+- (NSArray<id> *)mgl_coordinates {
+ NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:self.pointCount];
+ for (NSUInteger index = 0; index < self.pointCount; index++) {
+ CLLocationCoordinate2D coordinate = self.coordinates[index];
+ [coordinates addObject:@[@(coordinate.longitude), @(coordinate.latitude)]];
+ }
+ return [coordinates copy];
+}
+
- (BOOL)isEqual:(id)other {
return self == other || ([other isKindOfClass:[MGLPolyline class]] && [super isEqual:other]);
}
@@ -63,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;
@@ -82,7 +94,6 @@
}
traveled += (MGLDistanceBetweenRadianCoordinates(from, to) * mbgl::util::EARTH_RADIUS_M);
-
}
}
@@ -112,7 +123,7 @@
@interface MGLMultiPolyline ()
-@property (nonatomic, copy, readwrite) NS_ARRAY_OF(MGLPolyline *) *polylines;
+@property (nonatomic, copy, readwrite) NSArray<MGLPolyline *> *polylines;
@end
@@ -122,11 +133,11 @@
@synthesize overlayBounds = _overlayBounds;
-+ (instancetype)multiPolylineWithPolylines:(NS_ARRAY_OF(MGLPolyline *) *)polylines {
++ (instancetype)multiPolylineWithPolylines:(NSArray<MGLPolyline *> *)polylines {
return [[self alloc] initWithPolylines:polylines];
}
-- (instancetype)initWithPolylines:(NS_ARRAY_OF(MGLPolyline *) *)polylines {
+- (instancetype)initWithPolylines:(NSArray<MGLPolyline *> *)polylines {
if (self = [super init]) {
_polylines = polylines;
diff --git a/platform/darwin/src/MGLPolyline_Private.h b/platform/darwin/src/MGLPolyline_Private.h
new file mode 100644
index 0000000000..ff4fabaa78
--- /dev/null
+++ b/platform/darwin/src/MGLPolyline_Private.h
@@ -0,0 +1,12 @@
+#import "MGLPolyline.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MGLPolyline (Private)
+
+- (NSArray<id> *)mgl_coordinates;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
diff --git a/platform/darwin/src/MGLRasterDEMSource.h b/platform/darwin/src/MGLRasterDEMSource.h
new file mode 100644
index 0000000000..d439fe1645
--- /dev/null
+++ b/platform/darwin/src/MGLRasterDEMSource.h
@@ -0,0 +1,50 @@
+#import "MGLFoundation.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
+ <a href="https://en.wikipedia.org/wiki/Digital_elevation_model">digital elevation model</a>
+ (DEM) 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 DEM source is added to an `MGLStyle` object along with one or more
+ `MGLHillshadeStyleLayer` objects. Use a hillshade style layer to control the
+ appearance of content supplied by the raster DEM source.
+
+ Each
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-raster-dem"><code>raster-dem</code></a>
+ source defined by the style JSON file is represented at runtime by an
+ `MGLRasterDEMSource` 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:]`.
+
+ Currently, raster DEM sources only support the format used by
+ <a href="https://www.mapbox.com/help/access-elevation-data/#mapbox-terrain-rgb">Mapbox Terrain-RGB</a>.
+
+ ### Example
+
+ ```swift
+ let terrainRGBURL = URL(string: "mapbox://mapbox.terrain-rgb")!
+ let source = MGLRasterDEMSource(identifier: "hills", configurationURL: terrainRGBURL)
+ mapView.style?.addSource(source)
+ ```
+ */
+MGL_EXPORT
+@interface MGLRasterDEMSource : MGLRasterTileSource
+
+@end
diff --git a/platform/darwin/src/MGLRasterDEMSource.mm b/platform/darwin/src/MGLRasterDEMSource.mm
new file mode 100644
index 0000000000..27614b9ef4
--- /dev/null
+++ b/platform/darwin/src/MGLRasterDEMSource.mm
@@ -0,0 +1,17 @@
+#import "MGLRasterDEMSource.h"
+
+#import "MGLRasterTileSource_Private.h"
+#import "NSURL+MGLAdditions.h"
+
+#import <mbgl/style/sources/raster_dem_source.hpp>
+
+@implementation MGLRasterDEMSource
+
+- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize {
+ NSString *configurationURLString = configurationURL.mgl_URLByStandardizingScheme.absoluteString;
+ return std::make_unique<mbgl::style::RasterDEMSource>(identifier.UTF8String,
+ configurationURLString.UTF8String,
+ uint16_t(round(tileSize)));
+}
+
+@end
diff --git a/platform/darwin/src/MGLRasterSource_Private.h b/platform/darwin/src/MGLRasterSource_Private.h
deleted file mode 100644
index 76790bd053..0000000000
--- a/platform/darwin/src/MGLRasterSource_Private.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#import "MGLRasterSource.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface MGLRasterSource (Private)
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLRasterStyleLayer.h b/platform/darwin/src/MGLRasterStyleLayer.h
index 53a6a98b8a..bca9649e5d 100644
--- a/platform/darwin/src/MGLRasterStyleLayer.h
+++ b/platform/darwin/src/MGLRasterStyleLayer.h
@@ -2,22 +2,28 @@
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLFoundation.h"
-#import "MGLStyleValue.h"
#import "MGLForegroundStyleLayer.h"
NS_ASSUME_NONNULL_BEGIN
/**
- An `MGLRasterStyleLayer` is a style layer that renders raster tiles on the map.
+ An `MGLRasterStyleLayer` is a style layer that renders georeferenced raster
+ 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. For example, you could use a raster
- style layer to render <a href="https://www.mapbox.com/satellite/">Mapbox
- Satellite</a> imagery, a <a
+ 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
href="https://www.mapbox.com/help/define-tileset/#raster-tilesets">raster tile
set</a> uploaded to Mapbox Studio, or a raster map authored in <a
href="https://tilemill-project.github.io/tilemill/">TileMill</a>, the classic
Mapbox Editor, or Mapbox Studio Classic.
+
+ Raster images may also be used as icons or patterns in a style layer. To
+ register an image for use as an icon or pattern, use the `-[MGLStyle
+ setImage:forName:]` method. To configure a point annotation’s image, use the
+ `MGLAnnotationImage` class.
You can access an existing raster style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
@@ -29,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
```swift
let layer = MGLRasterStyleLayer(identifier: "clouds", source: source)
- layer.rasterOpacity = MGLStyleValue(rawValue: 0.5)
+ layer.rasterOpacity = NSExpression(forConstantValue: 0.5)
mapView.style?.addLayer(layer)
```
*/
@@ -57,22 +63,25 @@ MGL_EXPORT
Increase or reduce the brightness of the image. The value is the maximum
brightness.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `1`. Set this property to `nil` to reset
- it to the default value.
+ 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.
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>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values between 0 and 1 inclusive
+ * 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *maximumRasterBrightness;
+@property (nonatomic, null_resettable) NSExpression *maximumRasterBrightness;
/**
The transition affecting any changes to this layer’s `maximumRasterBrightness` property.
@@ -81,28 +90,31 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition maximumRasterBrightnessTransition;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterBrightnessMax __attribute__((unavailable("Use maximumRasterBrightness instead.")));
+@property (nonatomic, null_resettable) NSExpression *rasterBrightnessMax __attribute__((unavailable("Use maximumRasterBrightness instead.")));
/**
Increase or reduce the brightness of the image. The value is the minimum
brightness.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
+ 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.
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>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values between 0 and 1 inclusive
+ * 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *minimumRasterBrightness;
+@property (nonatomic, null_resettable) NSExpression *minimumRasterBrightness;
/**
The transition affecting any changes to this layer’s `minimumRasterBrightness` property.
@@ -111,23 +123,26 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition minimumRasterBrightnessTransition;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterBrightnessMin __attribute__((unavailable("Use minimumRasterBrightness instead.")));
+@property (nonatomic, null_resettable) NSExpression *rasterBrightnessMin __attribute__((unavailable("Use minimumRasterBrightness instead.")));
/**
Increase or reduce the contrast of the image.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
+ 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.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ * Constant numeric values between −1 and 1 inclusive
+ * 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) MGLStyleValue<NSNumber *> *rasterContrast;
+@property (nonatomic, null_resettable) NSExpression *rasterContrast;
/**
The transition affecting any changes to this layer’s `rasterContrast` property.
@@ -141,47 +156,46 @@ MGL_EXPORT
This property is measured in milliseconds.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `300`. Set this property to `nil` to
- reset it to the default value.
+ 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.
+
+ You can set this property to an expression containing any of the following:
- You can set this property to an instance of:
+ * Constant numeric values no less than 0
+ * 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterFadeDuration;
-
-/**
- The transition affecting any changes to this layer’s `rasterFadeDuration` property.
-
- This property corresponds to the `raster-fade-duration-transition` property in the style JSON file format.
-*/
-@property (nonatomic) MGLTransition rasterFadeDurationTransition;
+@property (nonatomic, null_resettable) NSExpression *rasterFadeDuration;
/**
Rotates hues around the color wheel.
This property is measured in degrees.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
+ 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.
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>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ * Constant numeric 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) MGLStyleValue<NSNumber *> *rasterHueRotation;
+@property (nonatomic, null_resettable) NSExpression *rasterHueRotation;
/**
The transition affecting any changes to this layer’s `rasterHueRotation` property.
@@ -190,23 +204,26 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition rasterHueRotationTransition;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterHueRotate __attribute__((unavailable("Use rasterHueRotation instead.")));
+@property (nonatomic, null_resettable) NSExpression *rasterHueRotate __attribute__((unavailable("Use rasterHueRotation instead.")));
/**
The opacity at which the image will be drawn.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `1`. Set this property to `nil` to reset
- it to the default value.
+ 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.
+
+ You can set this property to an expression containing any of the following:
- You can set this property to an instance of:
+ * Constant numeric values between 0 and 1 inclusive
+ * 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterOpacity;
+@property (nonatomic, null_resettable) NSExpression *rasterOpacity;
/**
The transition affecting any changes to this layer’s `rasterOpacity` property.
@@ -218,18 +235,21 @@ MGL_EXPORT
/**
Increase or reduce the saturation of the image.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
+ 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.
+
+ You can set this property to an expression containing any of the following:
- You can set this property to an instance of:
+ * Constant numeric values between −1 and 1 inclusive
+ * 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterSaturation;
+@property (nonatomic, null_resettable) NSExpression *rasterSaturation;
/**
The transition affecting any changes to this layer’s `rasterSaturation` property.
diff --git a/platform/darwin/src/MGLRasterStyleLayer.mm b/platform/darwin/src/MGLRasterStyleLayer.mm
index c63fd23529..94a58409de 100644
--- a/platform/darwin/src/MGLRasterStyleLayer.mm
+++ b/platform/darwin/src/MGLRasterStyleLayer.mm
@@ -39,21 +39,21 @@
#pragma mark - Accessing the Paint Attributes
-- (void)setMaximumRasterBrightness:(MGLStyleValue<NSNumber *> *)maximumRasterBrightness {
+- (void)setMaximumRasterBrightness:(NSExpression *)maximumRasterBrightness {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(maximumRasterBrightness);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(maximumRasterBrightness);
self.rawLayer->setRasterBrightnessMax(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)maximumRasterBrightness {
+- (NSExpression *)maximumRasterBrightness {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getRasterBrightnessMax();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultRasterBrightnessMax());
+ propertyValue = self.rawLayer->getDefaultRasterBrightnessMax();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setMaximumRasterBrightnessTransition:(MGLTransition )transition {
@@ -74,28 +74,28 @@
return transition;
}
-- (void)setRasterBrightnessMax:(MGLStyleValue<NSNumber *> *)rasterBrightnessMax {
+- (void)setRasterBrightnessMax:(NSExpression *)rasterBrightnessMax {
}
-- (MGLStyleValue<NSNumber *> *)rasterBrightnessMax {
+- (NSExpression *)rasterBrightnessMax {
return self.maximumRasterBrightness;
}
-- (void)setMinimumRasterBrightness:(MGLStyleValue<NSNumber *> *)minimumRasterBrightness {
+- (void)setMinimumRasterBrightness:(NSExpression *)minimumRasterBrightness {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(minimumRasterBrightness);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(minimumRasterBrightness);
self.rawLayer->setRasterBrightnessMin(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)minimumRasterBrightness {
+- (NSExpression *)minimumRasterBrightness {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getRasterBrightnessMin();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultRasterBrightnessMin());
+ propertyValue = self.rawLayer->getDefaultRasterBrightnessMin();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setMinimumRasterBrightnessTransition:(MGLTransition )transition {
@@ -116,28 +116,28 @@
return transition;
}
-- (void)setRasterBrightnessMin:(MGLStyleValue<NSNumber *> *)rasterBrightnessMin {
+- (void)setRasterBrightnessMin:(NSExpression *)rasterBrightnessMin {
}
-- (MGLStyleValue<NSNumber *> *)rasterBrightnessMin {
+- (NSExpression *)rasterBrightnessMin {
return self.minimumRasterBrightness;
}
-- (void)setRasterContrast:(MGLStyleValue<NSNumber *> *)rasterContrast {
+- (void)setRasterContrast:(NSExpression *)rasterContrast {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(rasterContrast);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(rasterContrast);
self.rawLayer->setRasterContrast(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)rasterContrast {
+- (NSExpression *)rasterContrast {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getRasterContrast();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultRasterContrast());
+ propertyValue = self.rawLayer->getDefaultRasterContrast();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setRasterContrastTransition:(MGLTransition )transition {
@@ -158,56 +158,38 @@
return transition;
}
-- (void)setRasterFadeDuration:(MGLStyleValue<NSNumber *> *)rasterFadeDuration {
+- (void)setRasterFadeDuration:(NSExpression *)rasterFadeDuration {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(rasterFadeDuration);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(rasterFadeDuration);
self.rawLayer->setRasterFadeDuration(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)rasterFadeDuration {
+- (NSExpression *)rasterFadeDuration {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getRasterFadeDuration();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultRasterFadeDuration());
+ propertyValue = self.rawLayer->getDefaultRasterFadeDuration();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
-- (void)setRasterFadeDurationTransition:(MGLTransition )transition {
+- (void)setRasterHueRotation:(NSExpression *)rasterHueRotation {
MGLAssertStyleLayerIsValid();
- mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
- self.rawLayer->setRasterFadeDurationTransition(options);
-}
-
-- (MGLTransition)rasterFadeDurationTransition {
- MGLAssertStyleLayerIsValid();
-
- mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getRasterFadeDurationTransition();
- MGLTransition transition;
- transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
- transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
-
- return transition;
-}
-
-- (void)setRasterHueRotation:(MGLStyleValue<NSNumber *> *)rasterHueRotation {
- MGLAssertStyleLayerIsValid();
-
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(rasterHueRotation);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(rasterHueRotation);
self.rawLayer->setRasterHueRotate(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)rasterHueRotation {
+- (NSExpression *)rasterHueRotation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getRasterHueRotate();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultRasterHueRotate());
+ propertyValue = self.rawLayer->getDefaultRasterHueRotate();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setRasterHueRotationTransition:(MGLTransition )transition {
@@ -228,28 +210,28 @@
return transition;
}
-- (void)setRasterHueRotate:(MGLStyleValue<NSNumber *> *)rasterHueRotate {
+- (void)setRasterHueRotate:(NSExpression *)rasterHueRotate {
}
-- (MGLStyleValue<NSNumber *> *)rasterHueRotate {
+- (NSExpression *)rasterHueRotate {
return self.rasterHueRotation;
}
-- (void)setRasterOpacity:(MGLStyleValue<NSNumber *> *)rasterOpacity {
+- (void)setRasterOpacity:(NSExpression *)rasterOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(rasterOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(rasterOpacity);
self.rawLayer->setRasterOpacity(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)rasterOpacity {
+- (NSExpression *)rasterOpacity {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getRasterOpacity();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultRasterOpacity());
+ propertyValue = self.rawLayer->getDefaultRasterOpacity();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setRasterOpacityTransition:(MGLTransition )transition {
@@ -270,21 +252,21 @@
return transition;
}
-- (void)setRasterSaturation:(MGLStyleValue<NSNumber *> *)rasterSaturation {
+- (void)setRasterSaturation:(NSExpression *)rasterSaturation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(rasterSaturation);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(rasterSaturation);
self.rawLayer->setRasterSaturation(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)rasterSaturation {
+- (NSExpression *)rasterSaturation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getRasterSaturation();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultRasterSaturation());
+ propertyValue = self.rawLayer->getDefaultRasterSaturation();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setRasterSaturationTransition:(MGLTransition )transition {
diff --git a/platform/darwin/src/MGLRasterSource.h b/platform/darwin/src/MGLRasterTileSource.h
index 4f4b7c96c3..f27cbc285f 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
@@ -124,7 +127,7 @@ MGL_EXPORT
the default values.
@return An initialized tile source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NSArray<NSString *> *)tileURLTemplates options:(nullable NSDictionary<MGLTileSourceOption, id> *)options NS_DESIGNATED_INITIALIZER;
@end
diff --git a/platform/darwin/src/MGLRasterSource.mm b/platform/darwin/src/MGLRasterTileSource.mm
index 8fc18ba69d..61e9ef97fd 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,21 +28,26 @@ 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];
}
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize {
- auto source = std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String,
- configurationURL.mgl_URLByStandardizingScheme.absoluteString.UTF8String,
- uint16_t(round(tileSize)));
+ auto source = [self pendingSourceWithIdentifier:identifier configurationURL:configurationURL tileSize:tileSize];
return self = [super initWithPendingSource:std::move(source)];
}
-- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options {
+- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize {
+ NSString *configurationURLString = configurationURL.mgl_URLByStandardizingScheme.absoluteString;
+ return std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String,
+ configurationURLString.UTF8String,
+ uint16_t(round(tileSize)));
+}
+
+- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NSArray<NSString *> *)tileURLTemplates options:(nullable NSDictionary<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/MGLRasterTileSource_Private.h b/platform/darwin/src/MGLRasterTileSource_Private.h
new file mode 100644
index 0000000000..128dcb447d
--- /dev/null
+++ b/platform/darwin/src/MGLRasterTileSource_Private.h
@@ -0,0 +1,21 @@
+#import "MGLRasterTileSource.h"
+
+#include <memory>
+
+namespace mbgl {
+ namespace style {
+ class RasterSource;
+ }
+}
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MGLRasterTileSource (Private)
+
+@property (nonatomic, readonly) mbgl::style::RasterSource *rawSource;
+
+- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLRendererConfiguration.h b/platform/darwin/src/MGLRendererConfiguration.h
index fbc6fc564d..34c8e9628b 100644
--- a/platform/darwin/src/MGLRendererConfiguration.h
+++ b/platform/darwin/src/MGLRendererConfiguration.h
@@ -1,6 +1,6 @@
#import <Foundation/Foundation.h>
#import <mbgl/storage/default_file_source.hpp>
-#import <mbgl/map/mode.hpp>
+#import <mbgl/renderer/mode.hpp>
NS_ASSUME_NONNULL_BEGIN
@@ -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/MGLRendererFrontend.h b/platform/darwin/src/MGLRendererFrontend.h
index 76904d008b..2df67ca4e4 100644
--- a/platform/darwin/src/MGLRendererFrontend.h
+++ b/platform/darwin/src/MGLRendererFrontend.h
@@ -56,9 +56,9 @@ public:
return renderer.get();
}
- void onLowMemory() {
+ void reduceMemoryUse() {
if (!renderer) return;
- renderer->onLowMemory();
+ renderer->reduceMemoryUse();
}
private:
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..08f3276496 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>
@@ -39,7 +40,7 @@ MGL_EXPORT
/**
An array of shapes forming the shape collection.
*/
-@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLShape *) *shapes;
+@property (nonatomic, copy, readonly) NSArray<MGLShape *> *shapes;
/**
Creates and returns a shape collection consisting of the given shapes.
@@ -48,7 +49,7 @@ MGL_EXPORT
this array is copied to the new object.
@return A new shape collection object.
*/
-+ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes;
++ (instancetype)shapeCollectionWithShapes:(NSArray<MGLShape *> *)shapes;
@end
diff --git a/platform/darwin/src/MGLShapeCollection.mm b/platform/darwin/src/MGLShapeCollection.mm
index 03cab0043f..74e78a764a 100644
--- a/platform/darwin/src/MGLShapeCollection.mm
+++ b/platform/darwin/src/MGLShapeCollection.mm
@@ -6,11 +6,11 @@
@implementation MGLShapeCollection
-+ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes {
++ (instancetype)shapeCollectionWithShapes:(NSArray<MGLShape *> *)shapes {
return [[self alloc] initWithShapes:shapes];
}
-- (instancetype)initWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes {
+- (instancetype)initWithShapes:(NSArray<MGLShape *> *)shapes {
if (self = [super init]) {
_shapes = shapes.copy;
}
diff --git a/platform/darwin/src/MGLShapeSource.h b/platform/darwin/src/MGLShapeSource.h
index 7460c83f50..1fc00d4de0 100644
--- a/platform/darwin/src/MGLShapeSource.h
+++ b/platform/darwin/src/MGLShapeSource.h
@@ -1,12 +1,11 @@
-#import "MGLSource.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.
@@ -17,12 +16,13 @@ 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
+
+ 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 a shape source.
+
+ This option only affects point features within an `MGLShapeSource` object; it
+ is ignored when creating an `MGLComputedShapeSource` object.
*/
extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClustered;
@@ -30,6 +30,9 @@ 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;
@@ -38,19 +41,32 @@ extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius;
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
+
+ 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 attribute corresponds to the
+
+ 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.
*/
@@ -61,8 +77,8 @@ extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLeve
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
+
+ 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.
*/
@@ -72,8 +88,8 @@ 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
+
+ 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.
*/
@@ -87,6 +103,10 @@ extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionSimplificationT
`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>
@@ -119,6 +139,14 @@ MGL_EXPORT
/**
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
@@ -126,11 +154,19 @@ MGL_EXPORT
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options NS_DESIGNATED_INITIALIZER;
/**
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`.
@@ -147,11 +183,19 @@ MGL_EXPORT
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options NS_DESIGNATED_INITIALIZER;
/**
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
@@ -166,11 +210,19 @@ MGL_EXPORT
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier features:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)features options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options;
+- (instancetype)initWithIdentifier:(NSString *)identifier features:(NSArray<MGLShape<MGLFeature> *> *)features options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options;
/**
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
@@ -186,7 +238,7 @@ MGL_EXPORT
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NS_ARRAY_OF(MGLShape *) *)shapes options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options;
+- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NSArray<MGLShape *> *)shapes options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options;
#pragma mark Accessing a Source’s Content
@@ -239,7 +291,7 @@ MGL_EXPORT
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the source that match the predicate.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)featuresMatchingPredicate:(nullable NSPredicate *)predicate;
+- (NSArray<id <MGLFeature>> *)featuresMatchingPredicate:(nullable NSPredicate *)predicate;
@end
diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm
index 571cbdcc62..31e5867703 100644
--- a/platform/darwin/src/MGLShapeSource.mm
+++ b/platform/darwin/src/MGLShapeSource.mm
@@ -13,13 +13,76 @@
#include <mbgl/style/sources/geojson_source.hpp>
#include <mbgl/renderer/renderer.hpp>
-const MGLShapeSourceOption MGLShapeSourceOptionClustered = @"MGLShapeSourceOptionClustered";
+const MGLShapeSourceOption MGLShapeSourceOptionBuffer = @"MGLShapeSourceOptionBuffer";
const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius = @"MGLShapeSourceOptionClusterRadius";
-const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering = @"MGLShapeSourceOptionMaximumZoomLevelForClustering";
+const MGLShapeSourceOption MGLShapeSourceOptionClustered = @"MGLShapeSourceOptionClustered";
const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel = @"MGLShapeSourceOptionMaximumZoomLevel";
-const MGLShapeSourceOption MGLShapeSourceOptionBuffer = @"MGLShapeSourceOptionBuffer";
+const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering = @"MGLShapeSourceOptionMaximumZoomLevelForClustering";
+const MGLShapeSourceOption MGLShapeSourceOptionMinimumZoomLevel = @"MGLShapeSourceOptionMinimumZoomLevel";
const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLShapeSourceOptionSimplificationTolerance";
+mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NSDictionary<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 ()
@property (nonatomic, readwrite) NSDictionary *options;
@@ -29,7 +92,7 @@ const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLSh
@implementation MGLShapeSource
-- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(NS_DICTIONARY_OF(NSString *, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(NSDictionary<NSString *, id> *)options {
auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options);
auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, geoJSONOptions);
if (self = [super initWithPendingSource:std::move(source)]) {
@@ -38,7 +101,7 @@ const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLSh
return self;
}
-- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(NSDictionary<MGLShapeSourceOption, id> *)options {
auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options);
auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, geoJSONOptions);
if (self = [super initWithPendingSource:std::move(source)]) {
@@ -47,7 +110,7 @@ const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLSh
return self;
}
-- (instancetype)initWithIdentifier:(NSString *)identifier features:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)features options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier features:(NSArray<MGLShape<MGLFeature> *> *)features options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options {
for (id <MGLFeature> feature in features) {
if (![feature conformsToProtocol:@protocol(MGLFeature)]) {
[NSException raise:NSInvalidArgumentException format:@"The object %@ included in the features argument does not conform to the MGLFeature protocol.", feature];
@@ -57,7 +120,7 @@ const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLSh
return [self initWithIdentifier:identifier shape:shapeCollectionFeature options:options];
}
-- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NS_ARRAY_OF(MGLShape *) *)shapes options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NSArray<MGLShape *> *)shapes options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options {
MGLShapeCollection *shapeCollection = [MGLShapeCollection shapeCollectionWithShapes:shapes];
return [self initWithIdentifier:identifier shape:shapeCollection options:options];
}
@@ -90,7 +153,7 @@ const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLSh
NSStringFromClass([self class]), (void *)self, self.identifier, self.URL, self.shape];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)featuresMatchingPredicate:(nullable NSPredicate *)predicate {
+- (NSArray<id <MGLFeature>> *)featuresMatchingPredicate:(nullable NSPredicate *)predicate {
mbgl::optional<mbgl::style::Filter> optionalFilter;
if (predicate) {
@@ -105,57 +168,3 @@ const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLSh
}
@end
-
-mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options) {
- auto geoJSONOptions = mbgl::style::GeoJSONOptions();
-
- 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;
-}
diff --git a/platform/darwin/src/MGLShapeSource_Private.h b/platform/darwin/src/MGLShapeSource_Private.h
index 84eb5deed4..83872afcbc 100644
--- a/platform/darwin/src/MGLShapeSource_Private.h
+++ b/platform/darwin/src/MGLShapeSource_Private.h
@@ -9,10 +9,7 @@ namespace mbgl {
}
}
-@interface MGLShapeSource (Private)
-@end
-
MGL_EXPORT
-mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options);
+mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NSDictionary<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..814a09ed21 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
@@ -280,7 +241,7 @@ MGL_EXPORT
/**
A set containing the style’s sources.
*/
-@property (nonatomic, strong) NS_SET_OF(__kindof MGLSource *) *sources;
+@property (nonatomic, strong) NSSet<__kindof MGLSource *> *sources;
/**
Values describing animated transitions to changes on a style's individual
@@ -342,7 +303,7 @@ MGL_EXPORT
The layers included in the style, arranged according to their back-to-front
ordering on the screen.
*/
-@property (nonatomic, strong) NS_ARRAY_OF(__kindof MGLStyleLayer *) *layers;
+@property (nonatomic, strong) NSArray<__kindof MGLStyleLayer *> *layers;
/**
Returns a style layer with the given identifier in the current 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) NSArray<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 987ae5f063..3f9bfbf8ca 100644
--- a/platform/darwin/src/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
@@ -8,6 +8,8 @@
#import "MGLLineStyleLayer.h"
#import "MGLCircleStyleLayer.h"
#import "MGLSymbolStyleLayer.h"
+#import "MGLHeatmapStyleLayer.h"
+#import "MGLHillshadeStyleLayer.h"
#import "MGLRasterStyleLayer.h"
#import "MGLBackgroundStyleLayer.h"
#import "MGLOpenGLStyleLayer.h"
@@ -16,9 +18,9 @@
#import "MGLSource_Private.h"
#import "MGLLight_Private.h"
#import "MGLTileSource_Private.h"
-#import "MGLVectorSource.h"
-#import "MGLVectorSource+MGLAdditions.h"
-#import "MGLRasterSource.h"
+#import "MGLVectorTileSource_Private.h"
+#import "MGLRasterTileSource.h"
+#import "MGLRasterDEMSource.h"
#import "MGLShapeSource.h"
#import "MGLImageSource.h"
@@ -34,12 +36,15 @@
#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/raster_layer.hpp>
+#include <mbgl/style/layers/heatmap_layer.hpp>
+#include <mbgl/style/layers/hillshade_layer.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
#include <mbgl/style/sources/vector_source.hpp>
#include <mbgl/style/sources/raster_source.hpp>
+#include <mbgl/style/sources/raster_dem_source.hpp>
#include <mbgl/style/sources/image_source.hpp>
#import "NSDate+MGLAdditions.h"
@@ -77,7 +82,8 @@
@property (nonatomic, readonly, weak) MGLMapView *mapView;
@property (nonatomic, readonly) mbgl::style::Style *rawStyle;
@property (readonly, copy, nullable) NSURL *URL;
-@property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, NS_DICTIONARY_OF(NSObject *, MGLTextLanguage *) *) *localizedLayersByIdentifier;
+@property (nonatomic, readwrite, strong) NSMutableDictionary<NSString *, MGLOpenGLStyleLayer *> *openGLLayers;
+@property (nonatomic) NSMutableDictionary<NSString *, NSDictionary<NSObject *, MGLTextLanguage *> *> *localizedLayersByIdentifier;
@end
@@ -110,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;
@@ -184,9 +142,9 @@ static NSURL *MGLStyleURL_trafficNight;
#pragma mark Sources
-- (NS_SET_OF(__kindof MGLSource *) *)sources {
+- (NSSet<__kindof MGLSource *> *)sources {
auto rawSources = self.rawStyle->getSources();
- NS_MUTABLE_SET_OF(__kindof MGLSource *) *sources = [NSMutableSet setWithCapacity:rawSources.size()];
+ NSMutableSet<__kindof MGLSource *> *sources = [NSMutableSet setWithCapacity:rawSources.size()];
for (auto rawSource = rawSources.begin(); rawSource != rawSources.end(); ++rawSource) {
MGLSource *source = [self sourceFromMBGLSource:*rawSource];
[sources addObject:source];
@@ -194,7 +152,7 @@ static NSURL *MGLStyleURL_trafficNight;
return sources;
}
-- (void)setSources:(NS_SET_OF(__kindof MGLSource *) *)sources {
+- (void)setSources:(NSSet<__kindof MGLSource *> *)sources {
for (MGLSource *source in self.sources) {
[self removeSource:source];
}
@@ -219,18 +177,20 @@ static NSURL *MGLStyleURL_trafficNight;
}
- (MGLSource *)sourceFromMBGLSource:(mbgl::style::Source *)rawSource {
- if (MGLSource *source = rawSource->peer.empty() ? nil : mbgl::any_cast<SourceWrapper>(rawSource->peer).source) {
+ if (MGLSource *source = rawSource->peer.has_value() ? mbgl::util::any_cast<SourceWrapper>(rawSource->peer).source : nil) {
return source;
}
// 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>()) {
return [[MGLImageSource alloc] initWithRawSource:imageSource mapView:self.mapView];
} else {
@@ -265,7 +225,7 @@ static NSURL *MGLStyleURL_trafficNight;
[source removeFromMapView:self.mapView];
}
-- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
+- (nullable NSArray<MGLAttributionInfo *> *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
// It’d be incredibly convenient to use -sources here, but this operation
// depends on the sources being sorted in ascending order by creation, as
// with the std::vector used in mbgl.
@@ -285,10 +245,10 @@ static NSURL *MGLStyleURL_trafficNight;
#pragma mark Style layers
-- (NS_ARRAY_OF(__kindof MGLStyleLayer *) *)layers
+- (NSArray<__kindof MGLStyleLayer *> *)layers
{
auto layers = self.rawStyle->getLayers();
- NS_MUTABLE_ARRAY_OF(__kindof MGLStyleLayer *) *styleLayers = [NSMutableArray arrayWithCapacity:layers.size()];
+ NSMutableArray<__kindof MGLStyleLayer *> *styleLayers = [NSMutableArray arrayWithCapacity:layers.size()];
for (auto layer : layers) {
MGLStyleLayer *styleLayer = [self layerFromMBGLLayer:layer];
[styleLayers addObject:styleLayer];
@@ -296,7 +256,7 @@ static NSURL *MGLStyleURL_trafficNight;
return styleLayers;
}
-- (void)setLayers:(NS_ARRAY_OF(__kindof MGLStyleLayer *) *)layers {
+- (void)setLayers:(NSArray<__kindof MGLStyleLayer *> *)layers {
for (MGLStyleLayer *layer in self.layers) {
[self removeLayer:layer];
}
@@ -381,7 +341,7 @@ static NSURL *MGLStyleURL_trafficNight;
{
NSParameterAssert(rawLayer);
- if (MGLStyleLayer *layer = rawLayer->peer.empty() ? nil : mbgl::any_cast<LayerWrapper>(rawLayer->peer).layer) {
+ if (MGLStyleLayer *layer = rawLayer->peer.has_value() ? mbgl::util::any_cast<LayerWrapper>(&(rawLayer->peer))->layer : nil) {
return layer;
}
@@ -395,6 +355,10 @@ static NSURL *MGLStyleURL_trafficNight;
return [[MGLSymbolStyleLayer alloc] initWithRawLayer:symbolLayer];
} else if (auto rasterLayer = rawLayer->as<mbgl::style::RasterLayer>()) {
return [[MGLRasterStyleLayer alloc] initWithRawLayer:rasterLayer];
+ } else if (auto heatmapLayer = rawLayer->as<mbgl::style::HeatmapLayer>()) {
+ return [[MGLHeatmapStyleLayer alloc] initWithRawLayer:heatmapLayer];
+ } else if (auto hillshadeLayer = rawLayer->as<mbgl::style::HillshadeLayer>()) {
+ return [[MGLHillshadeStyleLayer alloc] initWithRawLayer:hillshadeLayer];
} else if (auto circleLayer = rawLayer->as<mbgl::style::CircleLayer>()) {
return [[MGLCircleStyleLayer alloc] initWithRawLayer:circleLayer];
} else if (auto backgroundLayer = rawLayer->as<mbgl::style::BackgroundLayer>()) {
@@ -522,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
@@ -638,122 +570,37 @@ 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 isKindOfClass:[MGLConstantStyleValue class]]) {
- NSString *textField = [(MGLConstantStyleValue<NSString *> *)layer.text rawValue];
- 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 = [MGLStyleValue<NSString *> valueWithRawValue:localizingString];
- }
- }
- else if ([layer.text isKindOfClass:[MGLCameraStyleFunction class]]) {
- MGLCameraStyleFunction *function = (MGLCameraStyleFunction<NSString *> *)layer.text;
- NSMutableDictionary *stops = function.stops.mutableCopy;
- NSMutableDictionary *cameraStops = [NSMutableDictionary dictionary];
- [stops enumerateKeysAndObjectsUsingBlock:^(NSNumber *zoomLevel, MGLConstantStyleValue<NSString *> *stop, BOOL *done) {
- NSString *textField = stop.rawValue;
- NSString *localizingString = stringByLocalizingString(textField);
- if (![textField isEqualToString:localizingString]) {
- MGLTextLanguage *textLanguage = [[MGLTextLanguage alloc] initWithTextLanguage:textField
- updatedTextField:localizingString];
- [cameraStops setObject:textLanguage forKey:zoomLevel];
- stops[zoomLevel] = [MGLStyleValue<NSString *> valueWithRawValue:localizingString];
- }
-
- }];
- if (cameraStops.count > 0) {
- [self.localizedLayersByIdentifier setObject:cameraStops forKey:layer.identifier];
- }
- function.stops = stops;
- layer.text = function;
- }
+ 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 isKindOfClass:[MGLConstantStyleValue class]]) {
- NSString *textField = [(MGLConstantStyleValue<NSString *> *)layer.text rawValue];
- [textFields enumerateKeysAndObjectsUsingBlock:^(NSObject *originalLanguage, MGLTextLanguage *textLanguage, BOOL *done) {
- if ([textLanguage.updatedTextField isEqualToString:textField]) {
- layer.text = [MGLStyleValue<NSString *> valueWithRawValue:textLanguage.originalTextField];
- }
- }];
-
- }
- else if ([layer.text isKindOfClass:[MGLCameraStyleFunction class]]) {
- MGLCameraStyleFunction *function = (MGLCameraStyleFunction<NSString *> *)layer.text;
- NSMutableDictionary *stops = function.stops.mutableCopy;
- [textFields enumerateKeysAndObjectsUsingBlock:^(NSObject *zoomKey, MGLTextLanguage *textLanguage, BOOL *done) {
- if ([zoomKey isKindOfClass:[NSNumber class]]) {
- NSNumber *zoomLevel = (NSNumber*)zoomKey;
- MGLConstantStyleValue<NSString *> *stop = [stops objectForKey:zoomLevel];
- NSString *textField = stop.rawValue;
- if ([textLanguage.updatedTextField isEqualToString:textField]) {
- stops[zoomLevel] = [MGLStyleValue<NSString *> valueWithRawValue:textLanguage.originalTextField];
- }
- }
- }];
-
- function.stops = stops;
- layer.text = function;
- }
-
- }];
-
- self.localizedLayersByIdentifier = [NSMutableDictionary dictionary];
- }
-}
-
-- (NS_SET_OF(MGLVectorSource *) *)mapboxStreetsSources {
- return [self.sources objectsPassingTest:^BOOL (__kindof MGLVectorSource * _Nonnull source, BOOL * _Nonnull stop) {
- return [source isKindOfClass:[MGLVectorSource class]] && source.mapboxStreets;
+ NSExpression *text = layer.text;
+ NSExpression *localizedText = [text mgl_expressionLocalizedIntoLocale:locale];
+ if (![localizedText isEqual:text]) {
+ layer.text = localizedText;
+ }
+ }
+}
+
+- (NSSet<MGLVectorTileSource *> *)mapboxStreetsSources {
+ return [self.sources objectsPassingTest:^BOOL (__kindof MGLVectorTileSource * _Nonnull source, BOOL * _Nonnull stop) {
+ return [source isKindOfClass:[MGLVectorTileSource class]] && source.mapboxStreets;
}];
}
-- (NS_ARRAY_OF(MGLStyleLayer *) *)placeStyleLayers {
+- (NSArray<MGLStyleLayer *> *)placeStyleLayers {
NSSet *streetsSourceIdentifiers = [self.mapboxStreetsSources valueForKey:@"identifier"];
NSSet *placeSourceLayerIdentifiers = [NSSet setWithObjects:@"marine_label", @"country_label", @"state_label", @"place_label", @"water_label", @"poi_label", @"rail_station_label", @"mountain_peak_label", nil];
@@ -763,7 +610,7 @@ static NSURL *MGLStyleURL_trafficNight;
return [self.layers filteredArrayUsingPredicate:isPlacePredicate];
}
-- (NS_ARRAY_OF(MGLStyleLayer *) *)roadStyleLayers {
+- (NSArray<MGLStyleLayer *> *)roadStyleLayers {
NSSet *streetsSourceIdentifiers = [self.mapboxStreetsSources valueForKey:@"identifier"];
NSPredicate *isPlacePredicate = [NSPredicate predicateWithBlock:^BOOL (MGLVectorStyleLayer * _Nullable layer, NSDictionary<NSString *, id> * _Nullable bindings) {
diff --git a/platform/darwin/src/MGLStyleLayer.h.ejs b/platform/darwin/src/MGLStyleLayer.h.ejs
index df42621c6d..05f450a4f8 100644
--- a/platform/darwin/src/MGLStyleLayer.h.ejs
+++ b/platform/darwin/src/MGLStyleLayer.h.ejs
@@ -9,10 +9,9 @@
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLFoundation.h"
-#import "MGLStyleValue.h"
#import "MGL<%-
(type === 'background' ? '' :
- (type === 'raster' ? 'Foreground' :
+ (type === 'raster' || type === 'hillshade' ? 'Foreground' :
'Vector'))
%>StyleLayer.h"
@@ -79,7 +78,7 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(property.name) %>) {
MGL_EXPORT
@interface MGL<%- camelize(type) %>StyleLayer : MGL<%-
(type === 'background' ? '' :
- (type === 'raster' ? 'Foreground' :
+ (type === 'raster' || type === 'hillshade' ? 'Foreground' :
'Vector'))
%>StyleLayer
<% if (type === 'background') { -%>
@@ -120,10 +119,10 @@ which it is added.
/**
<%- propertyDoc(property.name, property, type, 'layout').wrap(80, 1) %>
*/
-@property (nonatomic<% if (!property.required) { %>, null_resettable<% } if (property.getter) { %>, getter=<%- objCGetter(property) -%><% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(property.name) %>;
+@property (nonatomic<% if (!property.required) { %>, null_resettable<% } if (property.getter) { %>, getter=<%- objCGetter(property) -%><% } %>) NSExpression *<%- camelizeWithLeadingLowercase(property.name) %>;
<% if (property.original) { %>
-@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> __attribute__((unavailable("Use <%- camelizeWithLeadingLowercase(property.name) %> instead.")));
+@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) NSExpression *<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> __attribute__((unavailable("Use <%- camelizeWithLeadingLowercase(property.name) %> instead.")));
<% } -%>
<% } -%>
@@ -135,7 +134,7 @@ which it is added.
/**
<%- propertyDoc(property.name, property, type, 'paint').wrap(80, 1) %>
*/
-@property (nonatomic<% if (!property.required) { %>, null_resettable<% } if (property.getter) { %>, getter=<%- objCGetter(property) -%><% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(property.name) %>;
+@property (nonatomic<% if (!property.required) { %>, null_resettable<% } if (property.getter) { %>, getter=<%- objCGetter(property) -%><% } %>) NSExpression *<%- camelizeWithLeadingLowercase(property.name) %>;
<% if (property["transition"]) { -%>
/**
@@ -147,7 +146,7 @@ which it is added.
<% } -%>
<% if (property.original) { -%>
-@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> __attribute__((unavailable("Use <%- camelizeWithLeadingLowercase(property.name) %> instead.")));
+@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) NSExpression *<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> __attribute__((unavailable("Use <%- camelizeWithLeadingLowercase(property.name) %> instead.")));
<% } -%>
<% } -%>
diff --git a/platform/darwin/src/MGLStyleLayer.mm.ejs b/platform/darwin/src/MGLStyleLayer.mm.ejs
index da67cbd633..42940083b5 100644
--- a/platform/darwin/src/MGLStyleLayer.mm.ejs
+++ b/platform/darwin/src/MGLStyleLayer.mm.ejs
@@ -83,7 +83,7 @@ namespace mbgl {
return @(self.rawLayer->getSourceID().c_str());
}
-<% if (type !== 'raster') { -%>
+<% if (type !== 'raster' && type !== 'hillshade') { -%>
- (NSString *)sourceLayerIdentifier
{
MGLAssertStyleLayerIsValid();
@@ -118,52 +118,37 @@ namespace mbgl {
#pragma mark - Accessing the Layout Attributes
<% for (const property of layoutProperties) { -%>
-- (void)set<%- camelize(property.name) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCName(property) %> {
+- (void)set<%- camelize(property.name) %>:(NSExpression *)<%- objCName(property) %> {
MGLAssertStyleLayerIsValid();
<% if (property["property-function"]) { -%>
- auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toDataDrivenPropertyValue(<%- objCName(property) %>);
+ auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<<%- valueTransformerArguments(property)[0] %>>>(<%- objCName(property) %>);
<% } else { -%>
-<% if (property.type == "enum") { -%>
- auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toEnumPropertyValue(<%- objCName(property) %>);
-<% } else if (property.function == "piecewise-constant") { -%>
- auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue(<%- objCName(property) %>);
-<% } else { -%>
- auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toInterpolatablePropertyValue(<%- objCName(property) %>);
-<% } -%>
+ auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue<mbgl::style::PropertyValue<<%- valueTransformerArguments(property)[0] %>>>(<%- objCName(property) %>);
<% } -%>
self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
}
-- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCGetter(property) %> {
+- (NSExpression *)<%- objCGetter(property) %> {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>();
-<% if (property["property-function"]) { -%>
- if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toDataDrivenStyleValue(self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>());
- }
- return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toDataDrivenStyleValue(propertyValue);
-<% } else { -%>
-<% if (property.type == "enum") { -%>
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>());
+ propertyValue = self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>();
}
- return MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue);
+<% if (property.type === 'string') { -%>
+ NSExpression *expression = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toExpression(propertyValue);
+ return expression.mgl_expressionByReplacingTokensWithKeyPaths;
<% } else { -%>
- if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>());
- }
- return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(propertyValue);
-<% } -%>
+ return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toExpression(propertyValue);
<% } -%>
}
<% if (property.original) { -%>
-- (void)set<%- camelize(originalPropertyName(property)) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
+- (void)set<%- camelize(originalPropertyName(property)) %>:(NSExpression *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
}
-- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
+- (NSExpression *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
return self.<%- objCGetter(property) %>;
}
@@ -174,44 +159,31 @@ namespace mbgl {
#pragma mark - Accessing the Paint Attributes
<% for (const property of paintProperties) { -%>
-- (void)set<%- camelize(property.name) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCName(property) %> {
+- (void)set<%- camelize(property.name) %>:(NSExpression *)<%- objCName(property) %> {
MGLAssertStyleLayerIsValid();
-<% if (property["property-function"]) { -%>
- auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toDataDrivenPropertyValue(<%- objCName(property) %>);
+<% if (property.name === 'heatmap-color') { -%>
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::HeatmapColorPropertyValue>(heatmapColor);
+<% } else if (property["property-function"]) { -%>
+ auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<<%- valueTransformerArguments(property)[0] %>>>(<%- objCName(property) %>);
<% } else { -%>
-<% if (property.type == "enum") { -%>
- auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toEnumPropertyValue(<%- objCName(property) %>);
-<% } else if (property.function == "piecewise-constant") { -%>
- auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue(<%- objCName(property) %>);
-<% } else { -%>
- auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toInterpolatablePropertyValue(<%- objCName(property) %>);
-<% } -%>
+ auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue<mbgl::style::PropertyValue<<%- valueTransformerArguments(property)[0] %>>>(<%- objCName(property) %>);
<% } -%>
self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
}
-- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCGetter(property) %> {
+- (NSExpression *)<%- objCGetter(property) %> {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>();
-<% if (property["property-function"]) { -%>
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toDataDrivenStyleValue(self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>());
+ propertyValue = self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>();
}
- return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toDataDrivenStyleValue(propertyValue);
+<% if (property.type === 'string') { -%>
+ NSExpression *expression = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toExpression(propertyValue);
+ return expression.mgl_expressionByReplacingTokensWithKeyPaths;
<% } else { -%>
-<% if (property.type == "enum") { -%>
- if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>());
- }
- return MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue);
-<% } else { -%>
- if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>());
- }
- return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(propertyValue);
-<% } -%>
+ return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toExpression(propertyValue);
<% } -%>
}
<% if (property["transition"]) { -%>
@@ -236,10 +208,10 @@ namespace mbgl {
<% } -%>
<% if (property.original) { -%>
-- (void)set<%- camelize(originalPropertyName(property)) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
+- (void)set<%- camelize(originalPropertyName(property)) %>:(NSExpression *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
}
-- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
+- (NSExpression *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> {
return self.<%- objCGetter(property) %>;
}
<% } -%>
diff --git a/platform/darwin/src/MGLStyleValue.h b/platform/darwin/src/MGLStyleValue.h
index 9c9b1dc4d1..65f89c5909 100644
--- a/platform/darwin/src/MGLStyleValue.h
+++ b/platform/darwin/src/MGLStyleValue.h
@@ -6,485 +6,43 @@
NS_ASSUME_NONNULL_BEGIN
-/**
- Options for `MGLStyleFunction` objects.
- */
-typedef NSString *MGLStyleFunctionOption NS_STRING_ENUM;
+typedef NSString *MGLStyleFunctionOption NS_STRING_ENUM NS_UNAVAILABLE;
-/**
- An `NSNumber` object containing an integer that determines the style function's
- exponential interpolation base.
-
- The exponential interpolation base controls the rate at which the function’s
- output values increase. A value of 1 causes the function to increase linearly
- based on zoom level or attribute value. A higher exponential interpolation base
- causes the function’s output values to vary exponentially, increasing more rapidly
- towards the high end of the function’s range. The default value of this property
- is 1, for a linear curve.
+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.")));
- This attribute corresponds to the
- <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#function-base"><code>base</code></a>
- function property in the Mapbox Style Specification.
+extern MGL_EXPORT const MGLStyleFunctionOption MGLStyleFunctionOptionDefaultValue __attribute__((unavailable("Use +[NSExpression expressionForConditional:trueExpression:falseExpression:] instead.")));
- This option only applies to functions that use an
- `MGLInterpolationModeExponential` interpolation mode that are assigned to
- interpolatable style layer properties.
- */
-extern MGL_EXPORT const MGLStyleFunctionOption MGLStyleFunctionOptionInterpolationBase;
-
-/**
- An `MGLConstantStyleValue` object that specifies a default value that a style
- function can use when it can't otherwise determine a value.
-
- A default value can be used to set the value of a style layer property that
- is not otherwise set by a function. For example, a source function with a
- `MGLInterpolationModeCategorical` interpolation mode with stops that specify
- color values to use based on a feature's attributes would set any feature
- that does not have attributes that match the stop key values to this
- default value.
-
- This option only applies to `MGLSourceStyleFunction` and
- `MGLCompositeStyleFunction` functions.
- */
-extern MGL_EXPORT const MGLStyleFunctionOption MGLStyleFunctionOptionDefaultValue;
-
-/**
- The modes used to interpolate property values between map zoom level changes
- or over a range of feature attribute values.
- */
typedef NS_ENUM(NSUInteger, MGLInterpolationMode) {
- /**
- Values between two stops are interpolated linearly, or exponentially based on
- the `MGLStyleFunctionOptionInterpolationBase`. A higher interpolation base
- causes the function’s output values to vary exponentially, increasing more rapidly
- towards the high end of the function’s range. The default interpolation base of 1
- creates a linear interpolation. Use exponential interpolation mode to show values
- relative to stop keys.
- */
- MGLInterpolationModeExponential = 0,
- /**
- Values between two stops are not interpolated. Instead, properties are set
- to the value of the stop just less than the function input. Use interval
- interpolation mode to show values that fall within a range.
- */
- MGLInterpolationModeInterval,
- /**
- Values between two stops are not interpolated. Instead, properties are set
- to the value of the stop equal to the function input's key value. Use
- categorical interpolation mode to show values that fit into categories.
- */
- MGLInterpolationModeCategorical,
- /**
- Values between two stops are not interpolated. Instead, for any given feature, the
- style value matches a value in that feature’s attributes dictionary. Use identity
- interpolation mode to show attribute values that can be used as style values.
- */
- MGLInterpolationModeIdentity
-};
-
-/**
- An `MGLStyleValue` object is a generic container for a style attribute value.
- The layout and paint attribute properties of `MGLStyleLayer` can be set to
- `MGLStyleValue` objects.
-
- The `MGLStyleValue` class itself represents a class cluster. Under the hood, a
- particular `MGLStyleValue` object may be either an `MGLConstantStyleValue` to
- represent a constant value or one of the concrete subclasses of
- `MGLStyleFunction` to represent a value function. Do not initialize an
- `MGLStyleValue` object directly; instead, use one of the class factory methods
- to create an `MGLStyleValue` object.
+ 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.")));
- The `MGLStyleValue` class takes a generic parameter `T` that indicates the
- Foundation class being wrapped by this class. Common values for `T` include:
-
- <ul>
- <li><code>NSNumber</code> (for Boolean values and floating-point numbers)</li>
- <li><code>NSValue</code> (for <code>CGVector</code>, <code>NSEdgeInsets</code>, <code>UIEdgeInsets</code>, and enumerations)</li>
- <li><code>NSString</code></li>
- <li><code>NSColor</code> or <code>UIColor</code></li>
- <li><code>NSArray</code></li>
- </ul>
- */
-MGL_EXPORT
+MGL_EXPORT __attribute__((unavailable("Use NSExpression instead.")))
@interface MGLStyleValue<T> : NSObject
-
-#pragma mark Creating a Style Value
-
-/**
- Creates and returns an `MGLConstantStyleValue` object containing a raw value.
-
- @param rawValue The constant value contained by the object.
- @return An `MGLConstantStyleValue` object containing `rawValue`, which is
- treated as a constant value.
- */
-+ (instancetype)valueWithRawValue:(T)rawValue;
-
-#pragma mark Function values
-
-/**
- Creates and returns an `MGLCameraStyleFunction` object representing a linear camera
- function with one or more stops.
-
- @param stops A dictionary associating zoom levels with style values.
- @return An `MGLCameraStyleFunction` object with the given stops.
- */
-+ (instancetype)valueWithStops:(NS_DICTIONARY_OF(NSNumber *, MGLStyleValue<T> *) *)stops __attribute__((deprecated("Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]")));
-
-/**
- Creates and returns an `MGLCameraStyleFunction` object representing a camera
- function with an exponential interpolation base and one or more stops.
-
- @param interpolationBase The exponential base of the interpolation curve.
- @param stops A dictionary associating zoom levels with style values.
- @return An `MGLCameraStyleFunction` object with the given interpolation base and stops.
- */
-+ (instancetype)valueWithInterpolationBase:(CGFloat)interpolationBase stops:(NS_DICTIONARY_OF(NSNumber *, MGLStyleValue<T> *) *)stops __attribute__((deprecated("Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]")));
-
-/**
- Creates and returns an `MGLCameraStyleFunction` object representing a camera function
- with one or more stops.
-
- @param interpolationMode The mode used to interpolate property values between
- map zoom level changes.
- @param cameraStops A dictionary associating zoom levels with style values.
- @param options A dictionary containing `MGLStyleFunctionOption` values that
- specify how a function is applied.
- @return An `MGLCameraStyleFunction` object with the given interpolation mode,
- camera stops, and options.
- */
-+ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode cameraStops:(NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *)cameraStops options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options;
-
-/**
- Creates and returns an `MGLSourceStyleFunction` object representing a source function.
-
- @param interpolationMode The mode used to interpolate property values over a
- range of feature attribute values.
- @param sourceStops A dictionary associating feature attributes with style values.
- @param attributeName Specifies the feature attribute to take as the function
- input.
- @param options A dictionary containing `MGLStyleFunctionOption` values that
- specify how a function is applied.
- @return An `MGLSourceStyleFunction` object with the given interpolation mode,
- source stops, attribute name, and options.
- */
-+ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode sourceStops:(nullable NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *)sourceStops attributeName:(NSString *)attributeName options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options;
-
-/**
- Creates and returns an `MGLCompositeStyleFunction` object representing a composite
- function.
-
- @param interpolationMode The mode used to interpolate property values over a
- range of feature attribute values for each outer zoom level.
- @param compositeStops A dictionary associating feature attributes with style
- values.
- @param attributeName Specifies the feature attribute to take as the function
- input.
- @param options A dictionary containing `MGLStyleFunctionOption` values that
- specify how a function is applied.
- @return An `MGLCompositeStyleFunction` object with the given interpolation mode,
- composite stops, attribute name, and options.
- */
-+ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode compositeStops:(NS_DICTIONARY_OF(id, NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *) *)compositeStops attributeName:(NSString *)attributeName options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options;
-
@end
-/**
- An `MGLConstantStyleValue` object is a generic container for a style attribute
- value that remains constant as the zoom level changes. The layout and paint
- attribute properties of `MGLStyleLayer` objects can be set to
- `MGLConstantStyleValue` objects.
-
- The `MGLConstantStyleValue` class takes a generic parameter `T` that indicates
- the Foundation class being wrapped by this class.
- */
-MGL_EXPORT
+MGL_EXPORT __attribute__((unavailable("Use +[NSExpression expressionForConstantValue:] instead.")))
@interface MGLConstantStyleValue<T> : MGLStyleValue<T>
-
-#pragma mark Creating a Style Constant Value
-
-/**
- Creates and returns an `MGLConstantStyleValue` object containing a raw value.
-
- @param rawValue The constant value contained by the object.
- @return An `MGLConstantStyleValue` object containing `rawValue`, which is
- treated as a constant value.
- */
-+ (instancetype)valueWithRawValue:(T)rawValue;
-
-#pragma mark Initializing a Style Constant Value
-
-- (instancetype)init NS_UNAVAILABLE;
-
-/**
- Returns an `MGLConstantStyleValue` object containing a raw value.
-
- @param rawValue The value contained by the receiver.
- @return An `MGLConstantStyleValue` object containing `rawValue`.
- */
-- (instancetype)initWithRawValue:(T)rawValue NS_DESIGNATED_INITIALIZER;
-
-#pragma mark Accessing the Underlying Value
-
-/**
- The raw value contained by the receiver.
- */
-@property (nonatomic) T rawValue;
-
@end
@compatibility_alias MGLStyleConstantValue MGLConstantStyleValue;
-/**
- An `MGLStyleFunction` is a is an abstract superclass for functions that are
- defined by an `MGLCameraStyleFunction`, `MGLSourceStyleFunction`, or
- `MGLCompositeStyleFunction` object.
-
- Create instances of `MGLCameraStyleFunction`, `MGLSourceStyleFunction`, and
- `MGLCompositeStyleFunction` in order to use `MGLStyleFunction`'s methods. Do
- not create instances of `MGLStyleFunction` directly, and do not create your
- own subclasses of this class.
-
- The `MGLStyleFunction` class takes a generic parameter `T` that indicates the
- Foundation class being wrapped by this class.
- */
-MGL_EXPORT
+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>
-
-#pragma mark Creating a Style Function
-
-/**
- Creates and returns an `MGLCameraStyleFunction` object representing a camera
- function with a linear interpolation curve.
-
- @note Do not create function instances using this method unless it is required
- for backwards compatiblity with your application code.
-
- @param stops A dictionary associating zoom levels with style values.
- @return An `MGLCameraStyleFunction` object with the given stops.
- */
-+ (instancetype)functionWithStops:(NS_DICTIONARY_OF(NSNumber *, MGLStyleValue<T> *) *)stops __attribute__((deprecated("Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]")));
-
-/**
- Creates and returns an `MGLCameraStyleFunction` object representing a camera
- function with an interpolation curve controlled by the provided interpolation
- base.
-
- @note Do not create function instances using this method unless it is required
- for backwards compatiblity with your application code.
-
- @param interpolationBase The exponential base of the interpolation curve.
- @param stops A dictionary associating zoom levels with style values.
- @return An `MGLCameraStyleFunction` object with the given interpolation base and stops.
- */
-+ (instancetype)functionWithInterpolationBase:(CGFloat)interpolationBase stops:(NS_DICTIONARY_OF(NSNumber *, MGLStyleValue<T> *) *)stops __attribute__((deprecated("Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]")));
-
-#pragma mark Initializing a Style Function
-
-/**
- Returns an `MGLStyleFunction` object representing a camera function. If the
- function is set as a style layer property value, it will be interpreted
- as a camera function with an interpolation curve controlled by the provided
- interpolation base.
-
- @note Do not create instances of `MGLStyleFunction` unless it is required for
- backwards compatiblity with your application code. You should create and use
- instances of `MGLCameraStyleFunction` to specify how properties will
- be visualized at different zoom levels.
-
- @param interpolationBase The exponential base of the interpolation curve.
- @param stops A dictionary associating zoom levels with style values.
- @return An `MGLStyleFunction` object with the given interpolation base and stops.
- */
-- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NS_DICTIONARY_OF(NSNumber *, MGLStyleValue<T> *) *)stops __attribute__((deprecated("Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]")));
-
-#pragma mark Accessing the Parameters of a Function
-
-/**
- The modes used to interpolate property values between map zoom level changes or
- over a range of feature attribute values.
- */
-@property (nonatomic) MGLInterpolationMode interpolationMode;
-
-/**
- A dictionary associating zoom levels with style values.
- */
-@property (nonatomic, copy, nullable) NSDictionary *stops;
-
-/**
- The exponential interpolation base of the function’s interpolation curve.
-
- @note This property specifies the exponential base of the interpolation curve
- of `MGLCameraStyleFunction` and `MGLSourceStyleFunction` functions that use
- a `MGLInterpolationModeExponential` `interpolationMode`. Otherwise, it is
- ignored.
- */
-@property (nonatomic) CGFloat interpolationBase;
-
@end
-/**
- An `MGLCameraStyleFunction` is a value function defining a style value that changes
- as the zoom level changes. The layout and paint attribute properties of an
- `MGLStyleLayer` object can be set to `MGLCameraStyleFunction` objects. Use a camera
- function to create the illusion of depth and control data density.
-
- The `MGLCameraStyleFunction` class takes a generic parameter `T` that indicates the
- Foundation class being wrapped by this class.
- */
-MGL_EXPORT
+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>
-
-#pragma mark Creating a Camera Function
-
-/**
- Creates and returns an `MGLCameraStyleFunction` object representing a camera
- function with one or more stops.
-
- @param interpolationMode The mode used to interpolate property values between
- map zoom level changes.
- @param stops A dictionary associating zoom levels with style values.
- @param options A dictionary containing `MGLStyleFunctionOption` values that
- specify how a function is applied.
- @return An `MGLCameraStyleFunction` object with the given interpolation mode,
- camera stops, and options.
- */
-+ (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *)stops options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options;
-
-#pragma mark Accessing the Parameters of a Camera Function
-
-/**
- A dictionary associating zoom levels with style values.
-
- Each of the function’s stops is represented by one key-value pair in the
- dictionary. Each key in the dictionary is an `NSNumber` object containing a
- floating-point zoom level. Each value in the dictionary is an `MGLStyleValue`
- object containing the value of the style attribute when the map is at the
- associated zoom level. An `MGLStyleFunction` object may not be used recursively
- as a stop value.
- */
-@property (nonatomic, copy) NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *stops;
-
@end
-/**
- An `MGLSourceStyleFunction` is a value function defining a style value that
- changes with its properties. The layout and paint attribute properties of an
- `MGLStyleLayer` object can be set to `MGLSourceStyleFunction` objects.
- Use source functions to visually differentate types of features within the same
- layer or create data visualizations.
-
- The `MGLSourceStyleFunction` class takes a generic parameter `T` that indicates the
- Foundation class being wrapped by this class.
- */
-MGL_EXPORT
+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>
-
-#pragma mark Creating a Source Function
-
-/**
- Creates and returns an `MGLSourceStyleFunction` object representing a source
- function.
-
- @param interpolationMode The mode used to interpolate property values over a
- range of feature attribute values.
- @param stops A dictionary associating feature attributes with style values.
- @param attributeName Specifies the feature attribute to take as the function
- input.
- @param options A dictionary containing `MGLStyleFunctionOption` values that
- specify how a function is applied.
- @return An `MGLSourceStyleFunction` object with the given interpolation mode,
- source stops, attribute name, and options.
-*/
-+ (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(nullable NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *)stops attributeName:(NSString *)attributeName options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options;
-
-#pragma mark Accessing the Parameters of a Source Function
-
-/**
- A string that specifies the feature attribute key whose value be used as the function
- input.
-*/
-@property (nonatomic, copy) NSString *attributeName;
-
-/**
- A dictionary associating attribute values with style values.
-
- Each of the function’s stops is represented by one key-value pair in the
- dictionary. Each key in the dictionary is an object representing a feature
- attribute key or interpolation stop. Each value in the dictionary is an
- `MGLStyleValue` object containing the value to use when the function is given
- the associated attribute key. An `MGLStyleFunction` object may not be used
- recursively as a stop value.
- */
-@property (nonatomic, copy, nullable) NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *stops;
-
-/**
- An `MGLStyleValue` object containing the default value to use when there is
- no input to provide to the function.
- */
-@property (nonatomic, nullable) MGLStyleValue<T> *defaultValue;
-
@end
-/**
- An `MGLCompositeStyleFunction` is a value function defining a style value that
- changes with the feature attributes at each map zoom level. The layout and paint
- attribute properties of an `MGLStyleLayer` object can be set to
- `MGLCompositeStyleFunction` objects. Use composite functions to allow the
- appearance of a map feature to change with both its attributes and the map zoom
- level.
-
- The `MGLCompositeStyleFunction` class takes a generic parameter `T` that indicates the
- Foundation class being wrapped by this class.
- */
-MGL_EXPORT
+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>
-
-#pragma mark Creating a Composite Function
-
-/**
- Creates and returns an `MGLCompositeStyleFunction` object representing a composite
- function.
-
- @param interpolationMode The mode used to interpolate property values over a
- range of feature attribute values for each outer zoom level.
- @param stops A dictionary associating feature attributes with style values.
- @param attributeName Specifies the feature attribute to take as the function
- input.
- @param options A dictionary containing `MGLStyleFunctionOption` values that
- specify how a function is applied.
- @return An `MGLCompositeStyleFunction` object with the given interpolation mode,
- composite stops, attribute name, and options.
- */
-+ (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NS_DICTIONARY_OF(id, NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *) *)stops attributeName:(NSString *)attributeName options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options;
-
-#pragma mark Accessing the Parameters of a Composite Function
-
-/**
- A string that specifies the feature attribute key whose value be used as the function
- input.
- */
-@property (nonatomic, copy) NSString *attributeName;
-
-/**
- A dictionary associating attribute values with style values.
-
- Each of the function’s stops is represented by one key-value pair in the
- dictionary. Each key in the dictionary is an `NSNumber` object containing a
- floating-point zoom level. Each value in the dictionary is an inner nested
- dictionary. Each key in the nested dictionary is an object representing a feature
- attribute key or interpolation stop. Each value in the nested dictionary is an
- `MGLStyleValue` object containing the value to use when the function is given
- the associated attribute key. An `MGLStyleFunction` object may not be used
- recursively as a value inside the nested dictionary.
- */
-@property (nonatomic, copy) NS_DICTIONARY_OF(id, NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *) *stops;
-
-/**
- An `MGLStyleValue` object containing the default value to use when there is
- no input to provide to the function.
- */
-@property (nonatomic, nullable) MGLStyleValue<T> *defaultValue;
-
@end
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLStyleValue.mm b/platform/darwin/src/MGLStyleValue.mm
index 4dd6b550d8..5103b5f5cf 100644
--- a/platform/darwin/src/MGLStyleValue.mm
+++ b/platform/darwin/src/MGLStyleValue.mm
@@ -1,308 +1,46 @@
#import "MGLStyleValue_Private.h"
+#include <mbgl/style/expression/expression.hpp>
+
const MGLStyleFunctionOption MGLStyleFunctionOptionInterpolationBase = @"MGLStyleFunctionOptionInterpolationBase";
const MGLStyleFunctionOption MGLStyleFunctionOptionDefaultValue = @"MGLStyleFunctionOptionDefaultValue";
-@implementation MGLStyleValue
-
-+ (instancetype)valueWithRawValue:(id)rawValue {
- return [MGLConstantStyleValue valueWithRawValue:rawValue];
-}
-
-+ (instancetype)valueWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
- return [MGLCameraStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential stops:stops options:@{MGLStyleFunctionOptionInterpolationBase: @(interpolationBase)}];
-}
-
-+ (instancetype)valueWithStops:(NSDictionary *)stops {
- return [MGLCameraStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential stops:stops options:nil];
-}
-
-+ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode cameraStops:(NSDictionary *)cameraStops options:(NSDictionary *)options {
- return [MGLCameraStyleFunction functionWithInterpolationMode:interpolationMode stops:cameraStops options:options];
-}
-
-+ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode sourceStops:(NSDictionary *)sourceStops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
- return [MGLSourceStyleFunction functionWithInterpolationMode:interpolationMode stops:sourceStops attributeName:attributeName options:options];
-}
-
-+ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode compositeStops:(NSDictionary *)compositeStops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
- return [MGLCompositeStyleFunction functionWithInterpolationMode:interpolationMode stops:compositeStops attributeName:attributeName options:options];
-}
-
-@end
-
-@implementation MGLConstantStyleValue
-
-+ (instancetype)valueWithRawValue:(id)rawValue {
- return [[self alloc] initWithRawValue:rawValue];
-}
-
-- (instancetype)initWithRawValue:(id)rawValue {
- if (self = [super init]) {
- _rawValue = rawValue;
- }
- return self;
-}
-
-- (NSString *)description {
- return [self.rawValue description];
-}
-
-- (NSString *)debugDescription {
- return [self.rawValue debugDescription];
-}
-
-- (BOOL)isEqual:(MGLConstantStyleValue *)other {
- return [other isKindOfClass:[self class]] && [other.rawValue isEqual:self.rawValue];
-}
-
-- (NSUInteger)hash {
- return [self.rawValue hash];
-}
-
-@end
-
-@implementation MGLStyleFunction
-
-+ (instancetype)functionWithStops:(NSDictionary *)stops {
- return [MGLCameraStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential stops:stops options:nil];
-}
-
-+ (instancetype)functionWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
- return [MGLCameraStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential stops:stops options:@{MGLStyleFunctionOptionInterpolationBase: @(interpolationBase)}];
-}
-
-- (instancetype)init {
- if (self = [super init]) {
- self.interpolationBase = 1.0;
- self.stops = @{};
- }
- return self;
-}
-
-- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
- if (self = [super init]) {
- self.interpolationBase = interpolationBase;
- self.stops = stops;
- }
- return self;
-}
-
-- (NSString *)description {
- return [NSString stringWithFormat:@"<%@: %p, \
- stops = %@, \
- interpolationBase = %f>",
- NSStringFromClass([self class]), (void *)self,
- self.stops,
- self.interpolationBase];
-}
-
-- (BOOL)isEqual:(MGLStyleFunction *)other {
- return ([other isKindOfClass:[self class]]
- && [other.stops isEqualToDictionary:self.stops]
- && other.interpolationBase == self.interpolationBase);
-}
-
-- (NSUInteger)hash {
- return self.stops.hash + @(self.interpolationBase).hash;
-}
-
-@end
-
-@implementation MGLCameraStyleFunction
-
-@dynamic stops;
-
-+ (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops options:(NSDictionary *)options {
- return [[self alloc] initWithInterpolationMode:interpolationMode stops:stops options:options];
-}
-
-- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
- return [self initWithInterpolationMode:MGLInterpolationModeExponential stops:stops options:@{MGLStyleFunctionOptionInterpolationBase: @(interpolationBase)}];
-}
-
-- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops options:(NSDictionary *)options {
- if (![stops count]) {
- [NSException raise:NSInvalidArgumentException
- format:@"Camera functions must have at least one stop."];
- return {};
- }
-
- if (self = [super init]) {
- self.interpolationMode = interpolationMode;
- self.stops = stops;
-
- if ([options.allKeys containsObject:MGLStyleFunctionOptionInterpolationBase]) {
- if ([options[MGLStyleFunctionOptionInterpolationBase] isKindOfClass:[NSNumber class]]) {
- NSNumber *value = (NSNumber *)options[MGLStyleFunctionOptionInterpolationBase];
- self.interpolationBase = [value floatValue];
- } else {
- [NSException raise:NSInvalidArgumentException format:@"Interpolation base must be an NSNumber that represents a CGFloat."];
- }
- }
- }
- return self;
-}
-
-- (NSString *)description {
- return [NSString stringWithFormat:@"<%@: %p, \
- interpolationMode = %lu, \
- stops = %@, \
- interpolationBase = %f>",
- NSStringFromClass([self class]), (void *)self,
- (unsigned long)self.interpolationMode,
- self.stops,
- self.interpolationBase];
-}
-
-- (BOOL)isEqual:(MGLCameraStyleFunction *)other {
- return ([other isKindOfClass:[self class]]
- && other.interpolationMode == self.interpolationMode
- && [other.stops isEqualToDictionary:self.stops]
- && other.interpolationBase == self.interpolationBase);
-}
-
-- (NSUInteger)hash {
- return @(self.interpolationMode).hash + self.stops.hash + @(self.interpolationBase).hash;
-}
-
-@end
-
-@implementation MGLSourceStyleFunction
-
-@dynamic stops;
-
-+ (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
- return [[self alloc] initWithInterpolationMode:interpolationMode stops:stops attributeName:attributeName options:options];
-}
-
-- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
- return [self initWithInterpolationMode:MGLInterpolationModeExponential stops:stops attributeName:@"" options:@{MGLStyleFunctionOptionInterpolationBase: @(interpolationBase)}];
-}
-
-- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
- if (self = [super init]) {
- self.interpolationMode = interpolationMode;
- self.stops = stops;
- _attributeName = attributeName;
-
- if ([options.allKeys containsObject:MGLStyleFunctionOptionDefaultValue]) {
- if ([options[MGLStyleFunctionOptionDefaultValue] isKindOfClass:[MGLStyleValue class]]) {
- MGLStyleValue *value = (MGLStyleValue *)options[MGLStyleFunctionOptionDefaultValue];
- _defaultValue = value;
- } else {
- [NSException raise:NSInvalidArgumentException format:@"Default value must be an MGLStyleValue"];
- }
+id MGLJSONObjectFromMBGLValue(const mbgl::Value &value) {
+ return value.match([](const mbgl::NullValue) -> id {
+ return [NSNull null];
+ }, [](const bool value) {
+ return @(value);
+ }, [](const float value) {
+ return @(value);
+ }, [](const int64_t value) {
+ return @(value);
+ }, [](const double value) {
+ return @(value);
+ }, [](const std::string &value) {
+ return @(value.c_str());
+ }, [](const mbgl::Color &value) {
+ return [MGLColor mgl_colorWithColor:value];
+ }, [](const mbgl::style::Position &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::Value> &vector) {
+ NSMutableArray *array = [NSMutableArray arrayWithCapacity:vector.size()];
+ for (auto value : vector) {
+ [array addObject:MGLJSONObjectFromMBGLValue(value)];
}
-
- if ([options.allKeys containsObject:MGLStyleFunctionOptionInterpolationBase]) {
- if ([options[MGLStyleFunctionOptionInterpolationBase] isKindOfClass:[NSNumber class]]) {
- NSNumber *value = (NSNumber *)options[MGLStyleFunctionOptionInterpolationBase];
- self.interpolationBase = [value floatValue];
- } else {
- [NSException raise:NSInvalidArgumentException format:@"Interpolation base must be an NSNumber that represents a CGFloat."];
- }
+ 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 self;
+ return dictionary;
+ }, [](const auto &) -> id {
+ return nil;
+ });
}
-- (NSString *)description {
- return [NSString stringWithFormat:@"<%@: %p, \
- interpolationMode = %lu, \
- stops = %@, \
- attributeName = %@, \
- defaultValue = %@, \
- interpolationBase = %f>",
- NSStringFromClass([self class]),
- (void *)self,
- (unsigned long)self.interpolationMode,
- self.stops,
- self.attributeName,
- self.defaultValue,
- self.interpolationBase];
+id MGLJSONObjectFromMBGLExpression(const mbgl::style::expression::Expression &mbglExpression) {
+ return MGLJSONObjectFromMBGLValue(mbglExpression.serialize());
}
-
-- (BOOL)isEqual:(MGLSourceStyleFunction *)other {
- return ([other isKindOfClass:[self class]]
- && other.interpolationMode == self.interpolationMode
- && ((self.stops && [other.stops isEqualToDictionary:self.stops]) || (!self.stops && !other.stops))
- && [other.attributeName isEqual:self.attributeName]
- && ((self.defaultValue && [other.defaultValue isEqual:self.defaultValue]) || (!self.defaultValue && !other.defaultValue))
- && other.interpolationBase == self.interpolationBase);
-}
-
-- (NSUInteger)hash {
- return @(self.interpolationMode).hash + self.stops.hash + self.attributeName.hash + self.defaultValue.hash + @(self.interpolationBase).hash;
-}
-
-@end
-
-@implementation MGLCompositeStyleFunction
-
-@dynamic stops;
-
-+ (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
- return [[self alloc] initWithInterpolationMode:interpolationMode stops:stops attributeName:attributeName options:options];
-}
-
-- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
- return [self initWithInterpolationMode:MGLInterpolationModeExponential stops:stops attributeName:@"" options:@{MGLStyleFunctionOptionInterpolationBase: @(interpolationBase)}];
-}
-
-- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
- if (self = [super init]) {
- self.interpolationMode = interpolationMode;
- self.stops = stops;
- _attributeName = attributeName;
-
- if ([options.allKeys containsObject:MGLStyleFunctionOptionDefaultValue]) {
- if ([options[MGLStyleFunctionOptionDefaultValue] isKindOfClass:[MGLStyleValue class]]) {
- MGLStyleValue *value = (MGLStyleValue *)options[MGLStyleFunctionOptionDefaultValue];
- _defaultValue = value;
- } else {
- [NSException raise:NSInvalidArgumentException format:@"Default value must be an MGLStyleValue"];
- }
- }
-
- if ([options.allKeys containsObject:MGLStyleFunctionOptionInterpolationBase]) {
- if ([options[MGLStyleFunctionOptionInterpolationBase] isKindOfClass:[NSNumber class]]) {
- NSNumber *value = (NSNumber *)options[MGLStyleFunctionOptionInterpolationBase];
- self.interpolationBase = [value floatValue];
- } else {
- [NSException raise:NSInvalidArgumentException format:@"Interpolation base must be an NSNumber that represents a CGFloat."];
- }
- }
- }
- return self;
-}
-
-- (NSString *)description {
- return [NSString stringWithFormat:@"<%@: %p, \
- interpolationMode = %lu, \
- stops = %@, \
- attributeName = %@, \
- defaultValue = %@, \
- interpolationBase = %f>",
- NSStringFromClass([self class]), (void *)self,
- (unsigned long)self.interpolationMode,
- self.stops,
- self.attributeName,
- self.defaultValue,
- self.interpolationBase];
-}
-
-- (BOOL)isEqual:(MGLCompositeStyleFunction *)other {
- return ([other isKindOfClass:[self class]]
- && other.interpolationMode == self.interpolationMode
- && [other.stops isEqualToDictionary:self.stops]
- && [other.attributeName isEqual:self.attributeName]
- && ((self.defaultValue && [other.defaultValue isEqual:self.defaultValue]) || (!self.defaultValue && !other.defaultValue))
- && other.interpolationBase == self.interpolationBase);
-}
-
-- (NSUInteger)hash {
- return @(self.interpolationMode).hash + self.stops.hash + self.attributeName.hash + @(self.interpolationBase).hash;
-}
-
-@end
diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h
index 2155c657bd..cc63793d0d 100644
--- a/platform/darwin/src/MGLStyleValue_Private.h
+++ b/platform/darwin/src/MGLStyleValue_Private.h
@@ -4,11 +4,14 @@
#import "NSValue+MGLStyleAttributeAdditions.h"
#import "NSValue+MGLAdditions.h"
+#import "NSExpression+MGLPrivateAdditions.h"
#import "MGLTypes.h"
#import "MGLConversion.h"
+#include <mbgl/style/conversion/property_value.hpp>
#include <mbgl/style/conversion/data_driven_property_value.hpp>
-#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion/heatmap_color_property_value.hpp>
+#include <mbgl/style/conversion/position.hpp>
#import <mbgl/style/types.hpp>
#import <mbgl/util/enum.hpp>
@@ -23,166 +26,101 @@
#import "NSColor+MGLAdditions.h"
#endif
+namespace mbgl {
+ namespace style {
+ namespace expression {
+ class Expression;
+ }
+ }
+}
+
+id MGLJSONObjectFromMBGLExpression(const mbgl::style::expression::Expression &mbglExpression);
+
template <typename MBGLType, typename ObjCType, typename MBGLElement = MBGLType, typename ObjCEnum = ObjCType>
class MGLStyleValueTransformer {
public:
-
- // Convert an mbgl property value into an mgl style value
- MGLStyleValue<ObjCType> *toStyleValue(const mbgl::style::PropertyValue<MBGLType> &mbglValue) {
- PropertyValueEvaluator evaluator;
+
+ /// Convert an mbgl property value into an mgl style value
+ NSExpression *toExpression(const mbgl::style::PropertyValue<MBGLType> &mbglValue) {
+ PropertyExpressionEvaluator evaluator;
return mbglValue.evaluate(evaluator);
}
-
- // Convert an mbgl data driven property value into an mgl style value
- MGLStyleValue<ObjCType> *toDataDrivenStyleValue(const mbgl::style::DataDrivenPropertyValue<MBGLType> &mbglValue) {
- PropertyValueEvaluator evaluator;
+
+ /// Convert an mbgl data driven property value into an mgl style value
+ template <typename MBGLEnum = MBGLType, typename MGLEnum = ObjCEnum>
+ NSExpression *toExpression(const mbgl::style::DataDrivenPropertyValue<MBGLEnum> &mbglValue) {
+ PropertyExpressionEvaluator evaluator;
return mbglValue.evaluate(evaluator);
}
-
- // Convert an mbgl property value containing an enum into an mgl style value
- template <typename MBGLEnum = MBGLType,
- class = typename std::enable_if<std::is_enum<MBGLEnum>::value>::type,
- typename MGLEnum = ObjCEnum,
- class = typename std::enable_if<std::is_enum<MGLEnum>::value>::type>
- MGLStyleValue<ObjCType> *toEnumStyleValue(const mbgl::style::PropertyValue<MBGLEnum> &mbglValue) {
- EnumPropertyValueEvaluator<MBGLEnum, ObjCEnum> evaluator;
- return mbglValue.evaluate(evaluator);
+
+ // Convert an mbgl heatmap color property value into an mgl style value
+ NSExpression *toExpression(const mbgl::style::HeatmapColorPropertyValue &mbglValue) {
+ if (mbglValue.isUndefined()) {
+ return nil;
+ }
+ return [NSExpression expressionWithMGLJSONObject:MGLJSONObjectFromMBGLExpression(mbglValue.getExpression())];
}
- // Convert an mgl style value into a non interpolatable (camera with interval stops) mbgl property value
- mbgl::style::PropertyValue<MBGLType> toPropertyValue(MGLStyleValue<ObjCType> *value) {
- if ([value isKindOfClass:[MGLSourceStyleFunction class]] || [value isKindOfClass:[MGLCompositeStyleFunction class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"This property can only be set to camera functions. Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:] instead."];
+ /**
+ Converts an NSExpression to an mbgl property value.
+ */
+ template <typename MBGLValue>
+ typename std::enable_if_t<!std::is_same<MBGLValue, mbgl::style::HeatmapColorPropertyValue>::value,
+ MBGLValue> toPropertyValue(NSExpression *expression) {
+ if (!expression) {
return {};
}
-
- if ([value isKindOfClass:[MGLConstantStyleValue class]]) {
- return toMBGLConstantValue((MGLConstantStyleValue<ObjCType> *)value);
- } else if ([value isKindOfClass:[MGLCameraStyleFunction class]]) {
- MGLCameraStyleFunction<ObjCType> *cameraStyleFunction = (MGLCameraStyleFunction<ObjCType> *)value;
- // Intentionally ignore the stop type set by the developer becuase non interpolatable property values
- // can only have interval stops. This also allows for backwards compatiblity when the developer uses
- // a deprecated MGLStyleValue method (that used to create an MGLStyleFunction) to create a function
- // for properties that are piecewise-constant (i.e. enum, bool, string)
- return toMBGLIntervalCameraFunction(cameraStyleFunction);
- } else if ([value isMemberOfClass:[MGLStyleFunction class]]) {
- MGLStyleFunction<ObjCType> *styleFunction = (MGLStyleFunction<ObjCType> *)value;
- return toMBGLIntervalCameraFunction(styleFunction);
- } else if (value) {
- [NSException raise:@"MGLAbstractClassException" format:
- @"The style value %@ cannot be applied to the style. "
- @"Make sure the style value was created as a member of a concrete subclass of MGLStyleValue.",
- NSStringFromClass([value class])];
- return {};
- } else {
- return {};
+
+ if (expression.expressionType == NSConstantValueExpressionType) {
+ MBGLType mbglValue;
+ getMBGLValue(expression.constantValue, mbglValue);
+ return mbglValue;
}
- }
-
- // Convert an mgl style value into a non interpolatable (camera with exponential or interval stops) mbgl property value
- mbgl::style::PropertyValue<MBGLType> toInterpolatablePropertyValue(MGLStyleValue<ObjCType> *value) {
- if ([value isKindOfClass:[MGLSourceStyleFunction class]] || [value isKindOfClass:[MGLCompositeStyleFunction class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"This property can only be set to camera functions. Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:] instead."];
- return {};
+ if (expression.expressionType == NSAggregateExpressionType) {
+ MBGLType mbglValue;
+ getMBGLValue(expression.collection, mbglValue);
+ return mbglValue;
}
-
- if ([value isKindOfClass:[MGLConstantStyleValue class]]) {
- return toMBGLConstantValue((MGLConstantStyleValue<ObjCType> *)value);
- } else if ([value isMemberOfClass:[MGLStyleFunction class]]) {
- MGLStyleFunction<ObjCType> *styleFunction = (MGLStyleFunction<ObjCType> *)value;
- return toMBGLExponentialCameraFunction(styleFunction);
- } else if ([value isKindOfClass:[MGLCameraStyleFunction class]]) {
- MGLCameraStyleFunction<ObjCType> *cameraStyleFunction = (MGLCameraStyleFunction<ObjCType> *)value;
- switch (cameraStyleFunction.interpolationMode) {
- case MGLInterpolationModeExponential:
- return toMBGLExponentialCameraFunction(cameraStyleFunction);
- break;
- case MGLInterpolationModeInterval:
- return toMBGLIntervalCameraFunction(cameraStyleFunction);
- break;
- default:
- [NSException raise:NSInvalidArgumentException
- format:@"A camera function must use either exponential or interval stops."];
- break;
- }
- return {};
- } else if (value) {
- [NSException raise:@"MGLAbstractClassException" format:
- @"The style value %@ cannot be applied to the style. "
- @"Make sure the style value was created as a member of a concrete subclass of MGLStyleValue.",
- NSStringFromClass([value class])];
- return {};
- } else {
+
+ NSArray *jsonExpression = expression.mgl_jsonExpressionObject;
+
+ mbgl::style::conversion::Error valueError;
+ auto value = mbgl::style::conversion::convert<MBGLValue>(
+ mbgl::style::conversion::makeConvertible(jsonExpression), valueError);
+ if (!value) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Invalid property value: %@", @(valueError.message.c_str())];
return {};
}
+
+ return *value;
}
-
- // Convert an mgl style value into a mbgl data driven property value
- mbgl::style::DataDrivenPropertyValue<MBGLType> toDataDrivenPropertyValue(MGLStyleValue<ObjCType> *value) {
- if ([value isKindOfClass:[MGLConstantStyleValue class]]) {
- return toMBGLConstantValue((MGLConstantStyleValue<ObjCType> *)value);
- } else if ([value isKindOfClass:[MGLStyleFunction class]]) {
- auto rawValue = toRawStyleSpecValue((MGLStyleFunction<ObjCType> *) value);
- mbgl::style::conversion::Error error;
- auto result = mbgl::style::conversion::convert<mbgl::style::DataDrivenPropertyValue<MBGLType>>(rawValue, error);
- NSCAssert(result, @(error.message.c_str()));
- return *result;
- } else {
+
+ /**
+ Converts an NSExpression to an mbgl property value.
+ */
+ template <typename MBGLValue>
+ typename std::enable_if_t<std::is_same<MBGLValue, mbgl::style::HeatmapColorPropertyValue>::value,
+ MBGLValue> toPropertyValue(NSExpression *expression) {
+ if (!expression) {
return {};
}
- }
-
- // Convert an mgl style value containing an enum into a mbgl property value containing an enum
- template <typename MBGLEnum = MBGLType,
- class = typename std::enable_if<std::is_enum<MBGLEnum>::value>::type,
- typename MGLEnum = ObjCEnum,
- class = typename std::enable_if<std::is_enum<MGLEnum>::value>::type>
- mbgl::style::PropertyValue<MBGLEnum> toEnumPropertyValue(MGLStyleValue<ObjCType> *value) {
- if ([value isKindOfClass:[MGLSourceStyleFunction class]] || [value isKindOfClass:[MGLCompositeStyleFunction class]]) {
+
+ NSArray *jsonExpression = expression.mgl_jsonExpressionObject;
+
+ mbgl::style::conversion::Error valueError;
+ auto value = mbgl::style::conversion::convert<mbgl::style::HeatmapColorPropertyValue>(
+ mbgl::style::conversion::makeConvertible(jsonExpression), valueError);
+ if (!value) {
[NSException raise:NSInvalidArgumentException
- format:@"This property can only be set to camera functions. Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:] instead."];
- return {};
- }
-
- if ([value isKindOfClass:[MGLConstantStyleValue class]]) {
- MBGLEnum mbglValue;
- getMBGLValue([(MGLConstantStyleValue<ObjCType> *)value rawValue], mbglValue);
- return mbglValue;
- } else if ([value isKindOfClass:[MGLCameraStyleFunction class]]) {
- MGLCameraStyleFunction<NSValue *> *cameraStyleFunction = (MGLCameraStyleFunction<NSValue *> *)value;
- __block std::map<float, MBGLType> stops = {};
- [cameraStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue<NSValue *> * _Nonnull stopValue, BOOL * _Nonnull stop) {
- NSCAssert([stopValue isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues");
- auto mbglStopValue = toEnumPropertyValue(stopValue);
- NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
- stops[zoomKey.floatValue] = mbglStopValue.asConstant();
- }];
-
- // Enumerations can only ever use interval stops.
- mbgl::style::IntervalStops<MBGLType> intervalStops = {stops};
-
- mbgl::style::CameraFunction<MBGLType> cameraFunction = {intervalStops};
- return cameraFunction;
- } else if (value) {
- [NSException raise:@"MGLAbstractClassException" format:
- @"The style value %@ cannot be applied to the style. "
- @"Make sure the style value was created as a member of a concrete subclass of MGLStyleValue.",
- NSStringFromClass([value class])];
- return {};
- } else {
+ format:@"Invalid property value: %@", @(valueError.message.c_str())];
return {};
}
+
+ return *value;
}
private: // Private utilities for converting from mgl to mbgl values
-
- MBGLType toMBGLConstantValue(MGLConstantStyleValue<ObjCType> *value) {
- MBGLType mbglValue;
- getMBGLValue(value.rawValue, mbglValue);
- return mbglValue;
- }
/**
As hack to allow converting enum => string values, we accept a second, dummy parameter in
@@ -220,164 +158,6 @@ private: // Private utilities for converting from mgl to mbgl values
return @(color.mgl_color.stringify().c_str());
}
-
- NSObject* toRawStyleSpecValue(MGLStyleFunction<ObjCType>* styleFunction) {
- NSMutableDictionary * rawFunction = [NSMutableDictionary new];
- // interpolationMode => type
- switch (styleFunction.interpolationMode) {
- case MGLInterpolationModeExponential:
- rawFunction[@"type"] = @"exponential";
- break;
- case MGLInterpolationModeInterval:
- rawFunction[@"type"] = @"interval";
- break;
- case MGLInterpolationModeCategorical:
- rawFunction[@"type"] = @"categorical";
- break;
- case MGLInterpolationModeIdentity:
- rawFunction[@"type"] = @"identity";
- break;
- }
-
- // interpolationBase => base
- if (styleFunction.interpolationBase) {
- rawFunction[@"base"] = @(styleFunction.interpolationBase);
- }
-
- // stops and default value
- if ([styleFunction isKindOfClass:[MGLCameraStyleFunction class]]) {
- // zoom-only function (no default value)
- __block NSMutableArray *stops = [[NSMutableArray alloc] init];
- [styleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLConstantStyleValue<ObjCType> * _Nonnull outputValue, BOOL * _Nonnull stop) {
- MBGLType dummyMbglValue;
- NSArray *rawStop = @[zoomKey, toRawStyleSpecValue([outputValue rawValue], dummyMbglValue)];
- [stops addObject:rawStop];
- }];
- rawFunction[@"stops"] = stops;
-
- } else if ([styleFunction isKindOfClass:[MGLSourceStyleFunction class]]) {
- auto sourceStyleFunction = (MGLSourceStyleFunction<ObjCType> *)styleFunction;
- rawFunction[@"property"] = sourceStyleFunction.attributeName;
- // property-only function
- __block NSMutableArray *stops = [[NSMutableArray alloc] init];
- [styleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSObject * _Nonnull propertyKey, MGLConstantStyleValue<ObjCType> * _Nonnull outputValue, BOOL * _Nonnull stop) {
- MBGLType dummyMbglValue;
- NSArray *rawStop = @[propertyKey, toRawStyleSpecValue([outputValue rawValue], dummyMbglValue)];
- [stops addObject:rawStop];
- }];
- rawFunction[@"stops"] = stops;
-
- // defaultValue => default
- if (sourceStyleFunction.defaultValue) {
- NSCAssert([sourceStyleFunction.defaultValue isKindOfClass:[MGLConstantStyleValue class]], @"Default value must be constant");
- MBGLType dummyMbglValue;
- rawFunction[@"default"] = toRawStyleSpecValue([(MGLConstantStyleValue<ObjCType> *)sourceStyleFunction.defaultValue rawValue], dummyMbglValue);
- }
- } else if ([styleFunction isKindOfClass:[MGLCompositeStyleFunction class]]) {
- // zoom-and-property function
- auto compositeStyleFunction = (MGLCompositeStyleFunction<ObjCType> *)styleFunction;
- rawFunction[@"property"] = compositeStyleFunction.attributeName;
-
- __block NSMutableArray *stops = [[NSMutableArray alloc] init];
- [compositeStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, NSDictionary * _Nonnull stopValue, BOOL * _Nonnull stop) {
- for (NSObject *valueKey in stopValue.allKeys) {
- NSDictionary *stopKey = @{
- @"zoom": zoomKey,
- @"value": valueKey
- };
- MGLConstantStyleValue<ObjCType> *outputValue = stopValue[valueKey];
- NSCAssert([outputValue isKindOfClass:[MGLConstantStyleValue<ObjCType> class]], @"Stop outputs should be MGLConstantStyleValues");
- MBGLType dummyMbglValue;
- NSArray *rawStop = @[stopKey, toRawStyleSpecValue([outputValue rawValue], dummyMbglValue)];
- [stops addObject:rawStop];
- }
- }];
- rawFunction[@"stops"] = stops;
-
- // defaultValue => default
- if (compositeStyleFunction.defaultValue) {
- NSCAssert([compositeStyleFunction.defaultValue isKindOfClass:[MGLConstantStyleValue class]], @"Default value must be constant");
- MBGLType dummyMbglValue;
- rawFunction[@"default"] = toRawStyleSpecValue([(MGLConstantStyleValue<ObjCType> *)compositeStyleFunction.defaultValue rawValue], dummyMbglValue);
- }
- }
-
- return rawFunction;
- }
-
- mbgl::style::CameraFunction<MBGLType> toMBGLExponentialCameraFunction(MGLStyleFunction<ObjCType> *styleFunction) {
- __block std::map<float, MBGLType> stops = {};
- [styleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue<ObjCType> * _Nonnull stopValue, BOOL * _Nonnull stop) {
- NSCAssert([stopValue isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues");
- auto mbglStopValue = toPropertyValue(stopValue);
- NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
- stops[zoomKey.floatValue] = mbglStopValue.asConstant();
- }];
-
- // Camera function with Exponential stops
- mbgl::style::ExponentialStops<MBGLType> exponentialStops = {stops, (float)styleFunction.interpolationBase};
- mbgl::style::CameraFunction<MBGLType> cameraFunction = {exponentialStops};
-
- return cameraFunction;
- }
-
- mbgl::style::CameraFunction<MBGLType> toMBGLIntervalCameraFunction(MGLStyleFunction<ObjCType> *styleFunction) {
- __block std::map<float, MBGLType> stops = {};
- [styleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue<ObjCType> * _Nonnull stopValue, BOOL * _Nonnull stop) {
- NSCAssert([stopValue isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues");
- auto mbglStopValue = toPropertyValue(stopValue);
- NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
- stops[zoomKey.floatValue] = mbglStopValue.asConstant();
- }];
-
- // Camera function with Interval stops
- mbgl::style::IntervalStops<MBGLType> intervalStops = {stops};
- mbgl::style::CameraFunction<MBGLType> cameraFunction = {intervalStops};
-
- return cameraFunction;
- }
-
- mbgl::style::SourceFunction<MBGLType> toMBGLCategoricalSourceFunction(MGLSourceStyleFunction<ObjCType> *sourceStyleFunction) {
- __block std::map<mbgl::style::CategoricalValue, MBGLType> stops = {};
- [sourceStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(id categoryKey, MGLStyleValue<ObjCType> *stopValue, BOOL *stop) {
- NSCAssert([stopValue isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues");
- auto mbglStopValue = toPropertyValue(stopValue);
- NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
-
- if ([categoryKey isKindOfClass:[NSString class]]) {
- const std::string& convertedValueKey = [((NSString *)categoryKey) UTF8String];
- stops[mbgl::style::CategoricalValue(convertedValueKey)] = mbglStopValue.asConstant();
- } else if ([categoryKey isKindOfClass:[NSNumber class]]) {
- NSNumber *key = (NSNumber *)categoryKey;
- if ((strcmp([key objCType], @encode(char)) == 0) ||
- (strcmp([key objCType], @encode(BOOL)) == 0)) {
- stops[mbgl::style::CategoricalValue((bool)[key boolValue])] = mbglStopValue.asConstant();
- } else if (strcmp([key objCType], @encode(double)) == 0 ||
- strcmp([key objCType], @encode(float)) == 0) {
- NSCAssert(mbglStopValue.isConstant(), @"Categorical stop keys must be strings, booleans, or integers");
- } else if ([key compare:@(0)] == NSOrderedDescending ||
- [key compare:@(0)] == NSOrderedSame ||
- [key compare:@(0)] == NSOrderedAscending) {
- stops[mbgl::style::CategoricalValue((int64_t)[key integerValue])] = mbglStopValue.asConstant();
- }
- }
- }];
- mbgl::style::CategoricalStops<MBGLType> categoricalStops = {stops};
- mbgl::style::SourceFunction<MBGLType> sourceFunction = {sourceStyleFunction.attributeName.UTF8String, categoricalStops};
- setDefaultMBGLValue(sourceStyleFunction, sourceFunction);
- return sourceFunction;
- }
-
- void setDefaultMBGLValue(MGLSourceStyleFunction<ObjCType> *sourceStyleFunction, mbgl::style::SourceFunction<MBGLType> &sourceFunction) {
- if (sourceStyleFunction.defaultValue) {
- NSCAssert([sourceStyleFunction.defaultValue isKindOfClass:[MGLConstantStyleValue class]], @"Default value must be constant");
- MBGLType mbglValue;
- id mglValue = [(MGLConstantStyleValue<ObjCType> *)sourceStyleFunction.defaultValue rawValue];
- getMBGLValue(mglValue, mbglValue);
- sourceFunction.defaultValue = mbglValue;
- }
- }
-
// Bool
void getMBGLValue(NSNumber *rawValue, bool &mbglValue) {
mbglValue = !!rawValue.boolValue;
@@ -394,13 +174,28 @@ private: // Private utilities for converting from mgl to mbgl values
}
// Offsets
- void getMBGLValue(NSValue *rawValue, std::array<float, 2> &mbglValue) {
- mbglValue = rawValue.mgl_offsetArrayValue;
+ void getMBGLValue(id rawValue, std::array<float, 2> &mbglValue) {
+ if ([rawValue isKindOfClass:[NSValue class]]) {
+ mbglValue = [rawValue mgl_offsetArrayValue];
+ } else if ([rawValue isKindOfClass:[NSArray class]]) {
+ NSArray *array = (NSArray *)rawValue;
+ getMBGLValue(array[0], mbglValue[0]);
+ getMBGLValue(array[1], mbglValue[1]);
+ }
}
// Padding
- void getMBGLValue(NSValue *rawValue, std::array<float, 4> &mbglValue) {
- mbglValue = rawValue.mgl_paddingArrayValue;
+ void getMBGLValue(id rawValue, std::array<float, 4> &mbglValue) {
+ if ([rawValue isKindOfClass:[NSValue class]]) {
+ mbglValue = [rawValue mgl_paddingArrayValue];
+ } else if ([rawValue isKindOfClass:[NSArray class]]) {
+ NSArray *array = (NSArray *)rawValue;
+ getMBGLValue(array[0], mbglValue[0]);
+ getMBGLValue(array[1], mbglValue[1]);
+ getMBGLValue(array[2], mbglValue[2]);
+ getMBGLValue(array[3], mbglValue[3]);
+ getMBGLValue(array[4], mbglValue[4]);
+ }
}
// Color
@@ -412,8 +207,12 @@ private: // Private utilities for converting from mgl to mbgl values
void getMBGLValue(ObjCType rawValue, std::vector<MBGLElement> &mbglValue) {
mbglValue.reserve(rawValue.count);
for (id obj in rawValue) {
+ id constantObject = obj;
+ if ([obj isKindOfClass:[NSExpression class]] && [obj expressionType] == NSConstantValueExpressionType) {
+ constantObject = [constantObject constantValue];
+ }
MBGLElement mbglElement;
- getMBGLValue(obj, mbglElement);
+ getMBGLValue(constantObject, mbglElement);
mbglValue.push_back(mbglElement);
}
}
@@ -429,11 +228,15 @@ private: // Private utilities for converting from mgl to mbgl values
class = typename std::enable_if<std::is_enum<MBGLEnum>::value>::type,
typename MGLEnum = ObjCEnum,
class = typename std::enable_if<std::is_enum<MGLEnum>::value>::type>
- void getMBGLValue(ObjCType rawValue, MBGLEnum &mbglValue) {
- MGLEnum mglEnum;
- [rawValue getValue:&mglEnum];
- auto str = mbgl::Enum<MGLEnum>::toString(mglEnum);
- mbglValue = *mbgl::Enum<MBGLEnum>::toEnum(str);
+ void getMBGLValue(id rawValue, MBGLEnum &mbglValue) {
+ if ([rawValue isKindOfClass:[NSString class]]) {
+ mbglValue = *mbgl::Enum<MBGLEnum>::toEnum([(NSString *)rawValue UTF8String]);
+ } else {
+ MGLEnum mglEnum;
+ [(NSValue *)rawValue getValue:&mglEnum];
+ auto str = mbgl::Enum<MGLEnum>::toString(mglEnum);
+ mbglValue = *mbgl::Enum<MBGLEnum>::toEnum(str);
+ }
}
private: // Private utilities for converting from mbgl to mgl values
@@ -477,7 +280,7 @@ private: // Private utilities for converting from mbgl to mgl values
static ObjCType toMGLRawStyleValue(const std::vector<MBGLElement> &mbglStopValue) {
NSMutableArray *array = [NSMutableArray arrayWithCapacity:mbglStopValue.size()];
for (const auto &mbglElement: mbglStopValue) {
- [array addObject:toMGLRawStyleValue(mbglElement)];
+ [array addObject:[NSExpression expressionForConstantValue:toMGLRawStyleValue(mbglElement)]];
}
return array;
}
@@ -496,212 +299,49 @@ private: // Private utilities for converting from mbgl to mgl values
return [NSValue value:&mglType withObjCType:@encode(MGLEnum)];
}
- // Converts mbgl stops to an equivilent NSDictionary for mgl
- static NSMutableDictionary *toConvertedStops(const std::map<float, MBGLType> &mbglStops) {
- NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.size()];
- for (const auto &mbglStop : mbglStops) {
- auto rawValue = toMGLRawStyleValue(mbglStop.second);
- stops[@(mbglStop.first)] = [MGLStyleValue valueWithRawValue:rawValue];
- }
- return stops;
- }
-
- // Converts mbgl interval stop categorical values to an equivilant object for mgl
- class CategoricalValueVisitor {
- public:
- id operator()(const bool value) {
- return toMGLRawStyleValue(value);
- }
-
- id operator()(const int64_t value) {
- return toMGLRawStyleValue(value);
- }
-
- id operator()(const std::string value) {
- return toMGLRawStyleValue(value);
- }
- };
-
- // Converts all types of mbgl property values containing enumerations into an equivilant mgl style value
- template <typename MBGLEnum = MBGLType, typename MGLEnum = ObjCEnum>
- class EnumPropertyValueEvaluator {
+ /// Converts all types of mbgl property values into an equivalent NSExpression.
+ class PropertyExpressionEvaluator {
public:
- id operator()(const mbgl::style::Undefined) const {
+ NSExpression *operator()(const mbgl::style::Undefined) const {
return nil;
}
- id operator()(const MBGLEnum &value) const {
- auto str = mbgl::Enum<MBGLEnum>::toString(value);
- MGLEnum mglType = *mbgl::Enum<MGLEnum>::toEnum(str);
- return [MGLConstantStyleValue<ObjCType> valueWithRawValue:[NSValue value:&mglType withObjCType:@encode(MGLEnum)]];
- }
-
- id operator()(const mbgl::style::CameraFunction<MBGLEnum> &mbglValue) const {
- CameraFunctionStopsVisitor visitor;
- return apply_visitor(visitor, mbglValue.stops);
- }
- };
-
- // Converts all possible mbgl camera function stops into an equivilant mgl style value
- class CameraFunctionStopsVisitor {
- public:
- id operator()(const mbgl::style::ExponentialStops<MBGLType> &mbglStops) {
- return [MGLCameraStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential
- stops:toConvertedStops(mbglStops.stops)
- options:@{MGLStyleFunctionOptionInterpolationBase: @(mbglStops.base)}];
- }
-
- id operator()(const mbgl::style::IntervalStops<MBGLType> &mbglStops) {
- return [MGLCameraStyleFunction functionWithInterpolationMode:MGLInterpolationModeInterval
- stops:toConvertedStops(mbglStops.stops)
- options:nil];
- }
- };
-
- // Converts a source function and all possible mbgl source function stops into an equivilant mgl style value
- class SourceFunctionStopsVisitor {
- public:
- id operator()(const mbgl::style::ExponentialStops<MBGLType> &mbglStops) {
- MGLSourceStyleFunction *sourceFunction = [MGLSourceStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential
- stops:toConvertedStops(mbglStops.stops)
- attributeName:@(mbglFunction.property.c_str())
- options:@{MGLStyleFunctionOptionInterpolationBase: @(mbglStops.base)}];
- if (mbglFunction.defaultValue) {
- sourceFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)];
- }
- return sourceFunction;
- }
-
- id operator()(const mbgl::style::IntervalStops<MBGLType> &mbglStops) {
- MGLSourceStyleFunction *sourceFunction = [MGLSourceStyleFunction functionWithInterpolationMode:MGLInterpolationModeInterval
- stops:toConvertedStops(mbglStops.stops)
- attributeName:@(mbglFunction.property.c_str())
- options:nil];
- if (mbglFunction.defaultValue) {
- sourceFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)];
- }
- return sourceFunction;
- }
-
- id operator()(const mbgl::style::CategoricalStops<MBGLType> &mbglStops) {
- NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.stops.size()];
- for (const auto &mbglStop : mbglStops.stops) {
- auto categoricalValue = mbglStop.first;
- auto rawValue = toMGLRawStyleValue(mbglStop.second);
- CategoricalValueVisitor categoricalValueVisitor;
- id stopKey = apply_visitor(categoricalValueVisitor, categoricalValue);
- stops[stopKey] = [MGLStyleValue valueWithRawValue:rawValue];
- }
-
- MGLSourceStyleFunction *sourceFunction = [MGLSourceStyleFunction functionWithInterpolationMode:MGLInterpolationModeCategorical
- stops:stops
- attributeName:@(mbglFunction.property.c_str())
- options:nil];
- if (mbglFunction.defaultValue) {
- sourceFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)];
- }
- return sourceFunction;
-
- }
-
- id operator()(const mbgl::style::IdentityStops<MBGLType> &mbglStops) {
- MGLSourceStyleFunction *sourceFunction = [MGLSourceStyleFunction functionWithInterpolationMode:MGLInterpolationModeIdentity
- stops:nil
- attributeName:@(mbglFunction.property.c_str()) options:nil];
- if (mbglFunction.defaultValue) {
- sourceFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)];
- }
- return sourceFunction;
- }
-
- const mbgl::style::SourceFunction<MBGLType> &mbglFunction;
- };
-
- // Converts a composite function and all possible mbgl stops into an equivilant mgl style value
- class CompositeFunctionStopsVisitor {
- public:
- id operator()(const mbgl::style::CompositeExponentialStops<MBGLType> &mbglStops) {
- NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.stops.size()];
- for (auto const& outerStop: mbglStops.stops) {
- stops[@(outerStop.first)] = toConvertedStops(outerStop.second);
- }
- MGLCompositeStyleFunction *compositeFunction = [MGLCompositeStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential
- stops:stops
- attributeName:@(mbglFunction.property.c_str())
- options:@{MGLStyleFunctionOptionInterpolationBase: @(mbglStops.base)}];
- if (mbglFunction.defaultValue) {
- compositeFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)];
- }
- return compositeFunction;
- }
-
- id operator()(const mbgl::style::CompositeIntervalStops<MBGLType> &mbglStops) {
- NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.stops.size()];
- for (auto const& outerStop: mbglStops.stops) {
- stops[@(outerStop.first)] = toConvertedStops(outerStop.second);
- }
- MGLCompositeStyleFunction *compositeFunction = [MGLCompositeStyleFunction functionWithInterpolationMode:MGLInterpolationModeInterval
- stops:stops
- attributeName:@(mbglFunction.property.c_str())
- options:nil];
- if (mbglFunction.defaultValue) {
- compositeFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)];
- }
- return compositeFunction;
- }
-
- id operator()(const mbgl::style::CompositeCategoricalStops<MBGLType> &mbglStops) {
- NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.stops.size()];
- for (auto const& outerStop: mbglStops.stops) {
- NSMutableDictionary *innerStops = [NSMutableDictionary dictionaryWithCapacity:outerStop.second.size()];
- for (const auto &mbglStop : outerStop.second) {
- auto categoricalValue = mbglStop.first;
- auto rawValue = toMGLRawStyleValue(mbglStop.second);
- CategoricalValueVisitor categoricalValueVisitor;
- id stopKey = apply_visitor(categoricalValueVisitor, categoricalValue);
- innerStops[stopKey] = [MGLStyleValue valueWithRawValue:rawValue];
- }
- stops[@(outerStop.first)] = innerStops;
- }
-
- MGLCompositeStyleFunction *compositeFunction = [MGLCompositeStyleFunction functionWithInterpolationMode:MGLInterpolationModeCategorical
- stops:stops attributeName:@(mbglFunction.property.c_str())
- options:nil];
- if (mbglFunction.defaultValue) {
- compositeFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)];
+ /**
+ As hack to allow converting enum => string values, we accept a second, dummy parameter in
+ the toRawStyleSpecValue() methods for converting 'atomic' (non-style-function) values.
+ This allows us to use `std::enable_if` to test (at compile time) whether or not MBGLType is an Enum.
+ */
+ template <typename MBGLEnum = MBGLType,
+ class = typename std::enable_if<!std::is_enum<MBGLEnum>::value>::type,
+ typename MGLEnum = ObjCEnum,
+ class = typename std::enable_if<!std::is_enum<MGLEnum>::value>::type>
+ NSExpression *operator()(const MBGLType &value) const {
+ id constantValue = toMGLRawStyleValue(value);
+ if ([constantValue isKindOfClass:[NSArray class]]) {
+ return [NSExpression expressionForAggregate:constantValue];
}
- return compositeFunction;
+ return [NSExpression expressionForConstantValue:constantValue];
}
-
- const mbgl::style::CompositeFunction<MBGLType> &mbglFunction;
- };
-
-
- // Converts all types of mbgl property values that don't contain enumerations into an equivilant mgl style value
- class PropertyValueEvaluator {
- public:
- id operator()(const mbgl::style::Undefined) const {
- return nil;
- }
-
- id operator()(const MBGLType &value) const {
- auto rawValue = toMGLRawStyleValue(value);
- return [MGLConstantStyleValue<ObjCType> valueWithRawValue:rawValue];
+
+ template <typename MBGLEnum = MBGLType,
+ class = typename std::enable_if<std::is_enum<MBGLEnum>::value>::type,
+ typename MGLEnum = ObjCEnum,
+ class = typename std::enable_if<std::is_enum<MGLEnum>::value>::type>
+ NSExpression *operator()(const MBGLEnum &value) const {
+ NSString *constantValue = @(mbgl::Enum<MBGLEnum>::toString(value));
+ return [NSExpression expressionForConstantValue:constantValue];
}
- id operator()(const mbgl::style::CameraFunction<MBGLType> &mbglValue) const {
- CameraFunctionStopsVisitor visitor;
- return apply_visitor(visitor, mbglValue.stops);
+ NSExpression *operator()(const mbgl::style::CameraFunction<MBGLType> &mbglValue) const {
+ return [NSExpression expressionWithMGLJSONObject:MGLJSONObjectFromMBGLExpression(mbglValue.getExpression())];
}
- id operator()(const mbgl::style::SourceFunction<MBGLType> &mbglValue) const {
- SourceFunctionStopsVisitor visitor { mbglValue };
- return apply_visitor(visitor, mbglValue.stops);
+ NSExpression *operator()(const mbgl::style::SourceFunction<MBGLType> &mbglValue) const {
+ return [NSExpression expressionWithMGLJSONObject:MGLJSONObjectFromMBGLExpression(mbglValue.getExpression())];
}
- MGLCompositeStyleFunction<ObjCType> * operator()(const mbgl::style::CompositeFunction<MBGLType> &mbglValue) const {
- CompositeFunctionStopsVisitor visitor { mbglValue };
- return apply_visitor(visitor, mbglValue.stops);
+ NSExpression *operator()(const mbgl::style::CompositeFunction<MBGLType> &mbglValue) const {
+ return [NSExpression expressionWithMGLJSONObject:MGLJSONObjectFromMBGLExpression(mbglValue.getExpression())];
}
};
};
diff --git a/platform/darwin/src/MGLStyle_Private.h b/platform/darwin/src/MGLStyle_Private.h
index 4cbe953a44..1294b9ad1c 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)
@@ -24,16 +24,16 @@ namespace mbgl {
@property (nonatomic, readonly, weak) MGLMapView *mapView;
@property (nonatomic, readonly) mbgl::style::Style *rawStyle;
-- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
-
-- (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration;
+- (nullable NSArray<MGLAttributionInfo *> *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
+@property (nonatomic, readonly, strong) NSMutableDictionary<NSString *, MGLOpenGLStyleLayer *> *openGLLayers;
+- (void)setStyleClasses:(NSArray<NSString *> *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration;
@end
@interface MGLStyle (MGLStreetsAdditions)
-@property (nonatomic, readonly, copy) NS_ARRAY_OF(MGLVectorStyleLayer *) *placeStyleLayers;
-@property (nonatomic, readonly, copy) NS_ARRAY_OF(MGLVectorStyleLayer *) *roadStyleLayers;
+@property (nonatomic, readonly, copy) NSArray<MGLVectorStyleLayer *> *placeStyleLayers;
+@property (nonatomic, readonly, copy) NSArray<MGLVectorStyleLayer *> *roadStyleLayers;
@end
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h
index ffb95dfc73..e27f039b75 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.h
+++ b/platform/darwin/src/MGLSymbolStyleLayer.h
@@ -2,7 +2,6 @@
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLFoundation.h"
-#import "MGLStyleValue.h"
#import "MGLVectorStyleLayer.h"
NS_ASSUME_NONNULL_BEGIN
@@ -68,14 +67,15 @@ typedef NS_ENUM(NSUInteger, MGLIconPitchAlignment) {
*/
MGLIconPitchAlignmentViewport,
/**
- Automatically matches the value of `iconRotationAlignment`.
+ Automatically matches the value of
+ `MGLSymbolStyleLayer.iconRotationAlignment`.
*/
MGLIconPitchAlignmentAuto,
};
/**
- In combination with `symbolPlacement`, determines the rotation behavior of
- icons.
+ In combination with `MGLSymbolStyleLayer.symbolPlacement`, determines the
+ rotation behavior of icons.
Values of this type are used in the `MGLSymbolStyleLayer.iconRotationAlignment`
property.
@@ -89,7 +89,7 @@ typedef NS_ENUM(NSUInteger, MGLIconRotationAlignment) {
MGLIconRotationAlignmentMap,
/**
Produces icons whose x-axes are aligned with the x-axis of the viewport,
- regardless of the value of `symbolPlacement`.
+ regardless of the value of `MGLSymbolStyleLayer.symbolPlacement`.
*/
MGLIconRotationAlignmentViewport,
/**
@@ -226,14 +226,15 @@ typedef NS_ENUM(NSUInteger, MGLTextPitchAlignment) {
*/
MGLTextPitchAlignmentViewport,
/**
- Automatically matches the value of `textRotationAlignment`.
+ Automatically matches the value of
+ `MGLSymbolStyleLayer.textRotationAlignment`.
*/
MGLTextPitchAlignmentAuto,
};
/**
- In combination with `symbolPlacement`, determines the rotation behavior of the
- individual glyphs forming the text.
+ In combination with `MGLSymbolStyleLayer.symbolPlacement`, determines the
+ rotation behavior of the individual glyphs forming the text.
Values of this type are used in the `MGLSymbolStyleLayer.textRotationAlignment`
property.
@@ -247,7 +248,7 @@ typedef NS_ENUM(NSUInteger, MGLTextRotationAlignment) {
MGLTextRotationAlignmentMap,
/**
Produces glyphs whose x-axes are aligned with the x-axis of the viewport,
- regardless of the value of `symbolPlacement`.
+ regardless of the value of `MGLSymbolStyleLayer.symbolPlacement`.
*/
MGLTextRotationAlignmentViewport,
/**
@@ -281,7 +282,7 @@ typedef NS_ENUM(NSUInteger, MGLTextTransform) {
};
/**
- Controls the translation reference point.
+ Controls the frame of reference for `MGLSymbolStyleLayer.iconTranslation`.
Values of this type are used in the `MGLSymbolStyleLayer.iconTranslationAnchor`
property.
@@ -298,7 +299,7 @@ typedef NS_ENUM(NSUInteger, MGLIconTranslationAnchor) {
};
/**
- Controls the translation reference point.
+ Controls the frame of reference for `MGLSymbolStyleLayer.textTranslation`.
Values of this type are used in the `MGLSymbolStyleLayer.textTranslationAnchor`
property.
@@ -318,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;
@@ -333,12 +335,12 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslationAnchor) {
```swift
let layer = MGLSymbolStyleLayer(identifier: "coffeeshops", source: pois)
layer.sourceLayerIdentifier = "pois"
- layer.iconImageName = MGLStyleValue(rawValue: "coffee")
- layer.iconScale = MGLStyleValue(rawValue: 0.5)
- layer.text = MGLStyleValue(rawValue: "{name}")
- layer.textTranslation = MGLStyleValue(rawValue: NSValue(cgVector: CGVector(dx: 10, dy: 0)))
- layer.textJustification = MGLStyleValue(rawValue: NSValue(mglTextJustification: .left))
- layer.textAnchor = MGLStyleValue(rawValue: NSValue(mglTextAnchor: .left))
+ layer.iconImageName = NSExpression(forConstantValue: "coffee")
+ layer.iconScale = NSExpression(forConstantValue: 0.5)
+ layer.text = NSExpression(forKeyPath: "name")
+ layer.textTranslation = NSExpression(forConstantValue: NSValue(cgVector: CGVector(dx: 10, dy: 0)))
+ layer.textJustification = NSExpression(forConstantValue: "left")
+ layer.textAnchor = NSExpression(forConstantValue: "left")
layer.predicate = NSPredicate(format: "%K == %@", "venue-type", "coffee")
mapView.style?.addLayer(layer)
```
@@ -367,9 +369,8 @@ MGL_EXPORT
If true, the icon will be visible even if it collides with other previously
drawn symbols.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing `NO`. Set this property to `nil` to reset it to
- the default value.
+ The default value of this property is an expression that evaluates to `NO`. 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.
@@ -378,51 +379,62 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-allow-overlap"><code>icon-allow-overlap</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant Boolean values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconAllowsOverlap;
+@property (nonatomic, null_resettable) NSExpression *iconAllowsOverlap;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconAllowOverlap __attribute__((unavailable("Use iconAllowsOverlap instead.")));
+@property (nonatomic, null_resettable) NSExpression *iconAllowOverlap __attribute__((unavailable("Use iconAllowsOverlap instead.")));
/**
Part of the icon placed closest to the anchor.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLIconAnchorCenter`. Set this property to `nil`
- to reset it to the default value.
+ The default value of this property is an expression that evaluates to `center`.
+ Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- */
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconAnchor;
+ You can set this property to an expression containing any of the following:
+
+ * Constant `MGLIconAnchor` values
+ * Any of the following constant string values:
+ * `center`: The center of the icon is placed closest to the anchor.
+ * `left`: The left side of the icon is placed closest to the anchor.
+ * `right`: The right side of the icon is placed closest to the anchor.
+ * `top`: The top of the icon is placed closest to the anchor.
+ * `bottom`: The bottom of the icon is placed closest to the anchor.
+ * `top-left`: The top left corner of the icon is placed closest to the
+ anchor.
+ * `top-right`: The top right corner of the icon is placed closest to the
+ anchor.
+ * `bottom-left`: The bottom left corner of the icon is placed closest to the
+ anchor.
+ * `bottom-right`: The bottom right corner of the icon is placed closest to
+ the anchor.
+ * 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 *iconAnchor;
/**
If true, other symbols can be visible even if they collide with the icon.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing `NO`. Set this property to `nil` to reset it to
- the default value.
+ The default value of this property is an expression that evaluates to `NO`. 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.
@@ -431,122 +443,119 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-ignore-placement"><code>icon-ignore-placement</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant Boolean values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconIgnoresPlacement;
+@property (nonatomic, null_resettable) NSExpression *iconIgnoresPlacement;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconIgnorePlacement __attribute__((unavailable("Use iconIgnoresPlacement instead.")));
+@property (nonatomic, null_resettable) NSExpression *iconIgnorePlacement __attribute__((unavailable("Use iconIgnoresPlacement instead.")));
/**
- Name of image in sprite to use for drawing an image background. A string with
- {tokens} replaced, referencing the data property to pull from.
+ 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>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ * Constant string 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) MGLStyleValue<NSString *> *iconImageName;
+@property (nonatomic, null_resettable) NSExpression *iconImageName;
-@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *iconImage __attribute__((unavailable("Use iconImageName instead.")));
+@property (nonatomic, null_resettable) NSExpression *iconImage __attribute__((unavailable("Use iconImageName instead.")));
#if TARGET_OS_IPHONE
/**
Offset distance of icon from its anchor.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing a `CGVector` struct set to 0 rightward and 0
downward. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- */
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconOffset;
+ You can set this property to an expression containing any of the following:
+
+ * Constant `CGVector` 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 *iconOffset;
#else
/**
Offset distance of icon from its anchor.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing a `CGVector` struct set to 0 rightward and 0
upward. Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
- You can set this property to an instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- */
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconOffset;
+ You can set this property to an expression containing any of the following:
+
+ * Constant `CGVector` 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 *iconOffset;
#endif
/**
If true, text will display without their corresponding icons when the icon
collides with other symbols and the text does not.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing `NO`. Set this property to `nil` to reset it to
- the default value.
+ The default value of this property is an expression that evaluates to `NO`. 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`, and
`text` is non-`nil`. Otherwise, it is ignored.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant Boolean values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable, getter=isIconOptional) MGLStyleValue<NSNumber *> *iconOptional;
+@property (nonatomic, null_resettable, getter=isIconOptional) NSExpression *iconOptional;
/**
Size of the additional area around the icon bounding box used for detecting
@@ -554,48 +563,59 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `2`. Set this property to `nil` to reset
- it to the default value.
+ 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.
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ * Constant numeric values no less than 0
+ * 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) MGLStyleValue<NSNumber *> *iconPadding;
+@property (nonatomic, null_resettable) NSExpression *iconPadding;
/**
Orientation of icon when map is pitched.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLIconPitchAlignmentAuto`. Set this property to
- `nil` to reset it to the default value.
+ The default value of this property is an expression that evaluates to `auto`.
+ Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant `MGLIconPitchAlignment` values
+ * Any of the following constant string values:
+ * `map`: The icon is aligned to the plane of the map.
+ * `viewport`: The icon is aligned to the plane of the viewport.
+ * `auto`: Automatically matches the value of `icon-rotation-alignment`.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconPitchAlignment;
+@property (nonatomic, null_resettable) NSExpression *iconPitchAlignment;
/**
Rotates the icon clockwise.
This property is measured in degrees.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
+ 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.
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
@@ -604,56 +624,61 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-rotate"><code>icon-rotate</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ * Constant numeric 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) MGLStyleValue<NSNumber *> *iconRotation;
+@property (nonatomic, null_resettable) NSExpression *iconRotation;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconRotate __attribute__((unavailable("Use iconRotation instead.")));
+@property (nonatomic, null_resettable) NSExpression *iconRotate __attribute__((unavailable("Use iconRotation instead.")));
/**
In combination with `symbolPlacement`, determines the rotation behavior of
icons.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLIconRotationAlignmentAuto`. Set this property
- to `nil` to reset it to the default value.
+ The default value of this property is an expression that evaluates to `auto`.
+ Set this property to `nil` to reset it to the default value.
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ * Constant `MGLIconRotationAlignment` values
+ * Any of the following constant string values:
+ * `map`: When `symbol-placement` is set to `point`, aligns icons east-west.
+ When `symbol-placement` is set to `line`, aligns icon x-axes with the line.
+ * `viewport`: Produces icons whose x-axes are aligned with the x-axis of the
+ viewport, regardless of the value of `symbol-placement`.
+ * `auto`: When `symbol-placement` is set to `point`, this is equivalent to
+ `viewport`. When `symbol-placement` is set to `line`, this is equivalent to
+ `map`.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
+
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconRotationAlignment;
+@property (nonatomic, null_resettable) NSExpression *iconRotationAlignment;
/**
Scales the original size of the icon by the provided factor. The new point size
- of the image will be the original point size multiplied by `iconSize`. 1 is the
- original size; 3 triples the size of the image.
+ of the image will be the original point size multiplied by `iconScale`. 1 is
+ the original size; 3 triples the size of the image.
This property is measured in factor of the original icon sizes.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `1`. Set this property to `nil` to reset
- it to the default value.
+ 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.
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
@@ -662,44 +687,49 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-size"><code>icon-size</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ * Constant numeric values no less than 0
+ * 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) MGLStyleValue<NSNumber *> *iconScale;
+@property (nonatomic, null_resettable) NSExpression *iconScale;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconSize __attribute__((unavailable("Use iconScale instead.")));
+@property (nonatomic, null_resettable) NSExpression *iconSize __attribute__((unavailable("Use iconScale instead.")));
/**
Scales the icon to fit around the associated text.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLIconTextFitNone`. Set this property to `nil` to
- reset it to the default value.
+ The default value of this property is an expression that evaluates to `none`.
+ 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`, and
`text` is non-`nil`. Otherwise, it is ignored.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ * Constant `MGLIconTextFit` values
+ * Any of the following constant string values:
+ * `none`: The icon is displayed at its intrinsic aspect ratio.
+ * `width`: The icon is scaled in the x-dimension to fit the width of the
+ text.
+ * `height`: The icon is scaled in the y-dimension to fit the height of the
+ text.
+ * `both`: The icon is scaled in both x- and y-dimensions.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
+
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTextFit;
+@property (nonatomic, null_resettable) NSExpression *iconTextFit;
#if TARGET_OS_IPHONE
/**
@@ -707,142 +737,160 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing `UIEdgeInsetsZero`. 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`, and
- `text` is non-`nil`, and `iconTextFit` is set to an `MGLStyleValue` object
- containing an `NSValue` object containing `MGLIconTextFitBoth`,
- `MGLIconTextFitWidth`, or `MGLIconTextFitHeight`. Otherwise, it is ignored.
+ `text` is non-`nil`, and `iconTextFit` is set to an expression that evaluates
+ to `MGLIconTextFitBoth`, `MGLIconTextFitWidth`, or `MGLIconTextFitHeight`.
+ Otherwise, it is ignored.
+
+ You can set this property to an expression containing any of the following:
- You can set this property to an instance of:
+ * Constant `UIEdgeInsets` 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTextFitPadding;
+@property (nonatomic, null_resettable) NSExpression *iconTextFitPadding;
#else
/**
Size of the additional area added to dimensions determined by `iconTextFit`.
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing `NSEdgeInsetsZero`. 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`, and
- `text` is non-`nil`, and `iconTextFit` is set to an `MGLStyleValue` object
- containing an `NSValue` object containing `MGLIconTextFitBoth`,
- `MGLIconTextFitWidth`, or `MGLIconTextFitHeight`. Otherwise, it is ignored.
+ `text` is non-`nil`, and `iconTextFit` is set to an expression that evaluates
+ to `MGLIconTextFitBoth`, `MGLIconTextFitWidth`, or `MGLIconTextFitHeight`.
+ Otherwise, it is ignored.
+
+ You can set this property to an expression containing any of the following:
- You can set this property to an instance of:
+ * Constant `NSEdgeInsets` 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTextFitPadding;
+@property (nonatomic, null_resettable) NSExpression *iconTextFitPadding;
#endif
/**
If true, the icon may be flipped to prevent it from being rendered upside-down.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing `NO`. Set this property to `nil` to reset it to
- the default value.
+ The default value of this property is an expression that evaluates to `NO`. 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`, and
- `iconRotationAlignment` is set to an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLIconRotationAlignmentMap`, and
- `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue`
- object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored.
+ `iconRotationAlignment` is set to an expression that evaluates to `map`, and
+ `symbolPlacement` is set to an expression that evaluates to `line`. Otherwise,
+ it is ignored.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-keep-upright"><code>icon-keep-upright</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant Boolean values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *keepsIconUpright;
+@property (nonatomic, null_resettable) NSExpression *keepsIconUpright;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconKeepUpright __attribute__((unavailable("Use keepsIconUpright instead.")));
+@property (nonatomic, null_resettable) NSExpression *iconKeepUpright __attribute__((unavailable("Use keepsIconUpright instead.")));
/**
If true, the text may be flipped vertically to prevent it from being rendered
upside-down.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing `YES`. Set this property to `nil` to reset it to
- the default value.
+ The default value of this property is an expression that evaluates to `YES`.
+ 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
- `textRotationAlignment` is set to an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLTextRotationAlignmentMap`, and
- `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue`
- object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored.
+ `textRotationAlignment` is set to an expression that evaluates to `map`, and
+ `symbolPlacement` is set to an expression that evaluates to `line`. Otherwise,
+ it is ignored.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-keep-upright"><code>text-keep-upright</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ * Constant Boolean values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
+
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *keepsTextUpright;
+@property (nonatomic, null_resettable) NSExpression *keepsTextUpright;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textKeepUpright __attribute__((unavailable("Use keepsTextUpright instead.")));
+@property (nonatomic, null_resettable) NSExpression *textKeepUpright __attribute__((unavailable("Use keepsTextUpright instead.")));
/**
Maximum angle change between adjacent characters.
This property is measured in degrees.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `45`. Set this property to `nil` to
- reset it to the default value.
+ 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.
This property is only applied to the style if `text` is non-`nil`, and
- `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue`
- object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored.
+ `symbolPlacement` is set to an expression that evaluates to `line`. Otherwise,
+ it is ignored.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-max-angle"><code>text-max-angle</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *maximumTextAngle;
+@property (nonatomic, null_resettable) NSExpression *maximumTextAngle;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textMaxAngle __attribute__((unavailable("Use maximumTextAngle instead.")));
+@property (nonatomic, null_resettable) NSExpression *textMaxAngle __attribute__((unavailable("Use maximumTextAngle instead.")));
/**
The maximum line width for text wrapping.
This property is measured in ems.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `10`. Set this property to `nil` to
- reset it to the default value.
+ 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.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
@@ -851,26 +899,19 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-max-width"><code>text-max-width</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ * Constant numeric values no less than 0
+ * 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) MGLStyleValue<NSNumber *> *maximumTextWidth;
+@property (nonatomic, null_resettable) NSExpression *maximumTextWidth;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textMaxWidth __attribute__((unavailable("Use maximumTextWidth instead.")));
+@property (nonatomic, null_resettable) NSExpression *textMaxWidth __attribute__((unavailable("Use maximumTextWidth instead.")));
/**
If true, the symbols will not cross tile edges to avoid mutual collisions.
@@ -878,102 +919,113 @@ MGL_EXPORT
prevent collisions, or if it is a point symbol layer placed after a line symbol
layer.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing `NO`. Set this property to `nil` to reset it to
- the default value.
+ The default value of this property is an expression that evaluates to `NO`. 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/#layout-symbol-symbol-avoid-edges"><code>symbol-avoid-edges</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ * Constant Boolean values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
+
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *symbolAvoidsEdges;
+@property (nonatomic, null_resettable) NSExpression *symbolAvoidsEdges;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *symbolAvoidEdges __attribute__((unavailable("Use symbolAvoidsEdges instead.")));
+@property (nonatomic, null_resettable) NSExpression *symbolAvoidEdges __attribute__((unavailable("Use symbolAvoidsEdges instead.")));
/**
Label placement relative to its geometry.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLSymbolPlacementPoint`. Set this property to
- `nil` to reset it to the default value.
+ The default value of this property is an expression that evaluates to `point`.
+ 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:
- You can set this property to an instance of:
+ * Constant `MGLSymbolPlacement` values
+ * Any of the following constant string values:
+ * `point`: The label is placed at the point where the geometry is located.
+ * `line`: The label is placed along the line of the geometry. Can only be
+ used on `LineString` and `Polygon` geometries.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *symbolPlacement;
+@property (nonatomic, null_resettable) NSExpression *symbolPlacement;
/**
Distance between two symbol anchors.
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `250`. Set this property to `nil` to
- reset it to the default value.
+ 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.
This property is only applied to the style if `symbolPlacement` is set to an
- `MGLStyleValue` object containing an `NSValue` object containing
- `MGLSymbolPlacementLine`. Otherwise, it is ignored.
+ expression that evaluates to `line`. Otherwise, it is ignored.
+
+ You can set this property to an expression containing any of the following:
- You can set this property to an instance of:
+ * Constant numeric values no less than 1
+ * 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *symbolSpacing;
+@property (nonatomic, null_resettable) NSExpression *symbolSpacing;
/**
- Value to use for a text label. Feature properties are specified using tokens
- like {field_name}. (Token replacement is only supported for literal
- `textField` values--not for property functions.)
+ Value to use for a text label.
- The default value of this property is an `MGLStyleValue` object containing the
- empty string. Set this property to `nil` to reset it to the default value.
+ 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.
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-field"><code>text-field</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ * Constant string 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) MGLStyleValue<NSString *> *text;
+@property (nonatomic, null_resettable) NSExpression *text;
-@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *textField __attribute__((unavailable("Use text instead.")));
+@property (nonatomic, null_resettable) NSExpression *textField __attribute__((unavailable("Use text instead.")));
/**
If true, the text will be visible even if it collides with other previously
drawn symbols.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing `NO`. Set this property to `nil` to reset it to
- the default value.
+ The default value of this property is an expression that evaluates to `NO`. 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.
@@ -982,44 +1034,56 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-allow-overlap"><code>text-allow-overlap</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant Boolean values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textAllowsOverlap;
+@property (nonatomic, null_resettable) NSExpression *textAllowsOverlap;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textAllowOverlap __attribute__((unavailable("Use textAllowsOverlap instead.")));
+@property (nonatomic, null_resettable) NSExpression *textAllowOverlap __attribute__((unavailable("Use textAllowsOverlap instead.")));
/**
Part of the text placed closest to the anchor.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLTextAnchorCenter`. Set this property to `nil`
- to reset it to the default value.
+ The default value of this property is an expression that evaluates to `center`.
+ 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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- */
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textAnchor;
+ You can set this property to an expression containing any of the following:
+
+ * Constant `MGLTextAnchor` values
+ * Any of the following constant string values:
+ * `center`: The center of the text is placed closest to the anchor.
+ * `left`: The left side of the text is placed closest to the anchor.
+ * `right`: The right side of the text is placed closest to the anchor.
+ * `top`: The top of the text is placed closest to the anchor.
+ * `bottom`: The bottom of the text is placed closest to the anchor.
+ * `top-left`: The top left corner of the text is placed closest to the
+ anchor.
+ * `top-right`: The top right corner of the text is placed closest to the
+ anchor.
+ * `bottom-left`: The bottom left corner of the text is placed closest to the
+ anchor.
+ * `bottom-right`: The bottom right corner of the text is placed closest to
+ the anchor.
+ * 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 *textAnchor;
/**
An array of font face names used to display the text.
@@ -1034,9 +1098,9 @@ MGL_EXPORT
the text, if the first font lacks a glyph for the character, the next font is
applied as a fallback, and so on.
- The default value of this property is an `MGLStyleValue` object containing the
- array `Open Sans Regular`, `Arial Unicode MS Regular`. Set this property to
- `nil` to reset it to the default value.
+ The default value of this property is an expression that evaluates to the array
+ `Open Sans Regular`, `Arial Unicode MS Regular`. 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.
@@ -1045,25 +1109,27 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-font"><code>text-font</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ * Constant array 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) MGLStyleValue<NSArray<NSString *> *> *textFontNames;
+@property (nonatomic, null_resettable) NSExpression *textFontNames;
-@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSString *> *> *textFont __attribute__((unavailable("Use textFontNames instead.")));
+@property (nonatomic, null_resettable) NSExpression *textFont __attribute__((unavailable("Use textFontNames instead.")));
/**
Font size.
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `16`. Set this property to `nil` to
- reset it to the default value.
+ 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.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
@@ -1072,33 +1138,25 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-size"><code>text-size</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ * Constant numeric values no less than 0
+ * 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) MGLStyleValue<NSNumber *> *textFontSize;
+@property (nonatomic, null_resettable) NSExpression *textFontSize;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textSize __attribute__((unavailable("Use textFontSize instead.")));
+@property (nonatomic, null_resettable) NSExpression *textSize __attribute__((unavailable("Use textFontSize instead.")));
/**
If true, other symbols can be visible even if they collide with the text.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing `NO`. Set this property to `nil` to reset it to
- the default value.
+ The default value of this property is an expression that evaluates to `NO`. 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.
@@ -1107,23 +1165,28 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-ignore-placement"><code>text-ignore-placement</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant Boolean values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textIgnoresPlacement;
+@property (nonatomic, null_resettable) NSExpression *textIgnoresPlacement;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textIgnorePlacement __attribute__((unavailable("Use textIgnoresPlacement instead.")));
+@property (nonatomic, null_resettable) NSExpression *textIgnorePlacement __attribute__((unavailable("Use textIgnoresPlacement instead.")));
/**
Text justification options.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLTextJustificationCenter`. Set this property to
- `nil` to reset it to the default value.
+ The default value of this property is an expression that evaluates to `center`.
+ 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.
@@ -1132,77 +1195,69 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-justify"><code>text-justify</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ * Constant `MGLTextJustification` values
+ * Any of the following constant string values:
+ * `left`: The text is aligned to the left.
+ * `center`: The text is centered.
+ * `right`: The text is aligned to the right.
+ * 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) MGLStyleValue<NSValue *> *textJustification;
+@property (nonatomic, null_resettable) NSExpression *textJustification;
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textJustify __attribute__((unavailable("Use textJustification instead.")));
+@property (nonatomic, null_resettable) NSExpression *textJustify __attribute__((unavailable("Use textJustification instead.")));
/**
Text tracking amount.
This property is measured in ems.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
+ 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.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ * Constant numeric 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) MGLStyleValue<NSNumber *> *textLetterSpacing;
+@property (nonatomic, null_resettable) NSExpression *textLetterSpacing;
/**
Text leading value for multi-line text.
This property is measured in ems.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `1.2`. Set this property to `nil` to
- reset it to the default value.
+ 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.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textLineHeight;
+@property (nonatomic, null_resettable) NSExpression *textLineHeight;
#if TARGET_OS_IPHONE
/**
@@ -1210,80 +1265,71 @@ MGL_EXPORT
This property is measured in ems.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing a `CGVector` struct set to 0 ems rightward and 0
ems downward. 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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- */
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textOffset;
+ You can set this property to an expression containing any of the following:
+
+ * Constant `CGVector` 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 *textOffset;
#else
/**
Offset distance of text from its anchor.
This property is measured in ems.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing a `CGVector` struct set to 0 ems rightward and 0
ems upward. 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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- */
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textOffset;
+ You can set this property to an expression containing any of the following:
+
+ * Constant `CGVector` 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 *textOffset;
#endif
/**
If true, icons will display without their corresponding text when the text
collides with other symbols and the icon does not.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing `NO`. Set this property to `nil` to reset it to
- the default value.
+ The default value of this property is an expression that evaluates to `NO`. 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
`iconImageName` is non-`nil`. Otherwise, it is ignored.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant Boolean values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable, getter=isTextOptional) MGLStyleValue<NSNumber *> *textOptional;
+@property (nonatomic, null_resettable, getter=isTextOptional) NSExpression *textOptional;
/**
Size of the additional area around the text bounding box used for detecting
@@ -1291,48 +1337,59 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `2`. Set this property to `nil` to reset
- it to the default value.
+ 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.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values no less than 0
+ * 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textPadding;
+@property (nonatomic, null_resettable) NSExpression *textPadding;
/**
Orientation of text when map is pitched.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLTextPitchAlignmentAuto`. Set this property to
- `nil` to reset it to the default value.
+ The default value of this property is an expression that evaluates to `auto`.
+ 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 instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ * Constant `MGLTextPitchAlignment` values
+ * Any of the following constant string values:
+ * `map`: The text is aligned to the plane of the map.
+ * `viewport`: The text is aligned to the plane of the viewport.
+ * `auto`: Automatically matches the value of `text-rotation-alignment`.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
+
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textPitchAlignment;
+@property (nonatomic, null_resettable) NSExpression *textPitchAlignment;
/**
Rotates the text clockwise.
This property is measured in degrees.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
+ 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.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
@@ -1341,73 +1398,75 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-rotate"><code>text-rotate</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ * Constant numeric 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) MGLStyleValue<NSNumber *> *textRotation;
+@property (nonatomic, null_resettable) NSExpression *textRotation;
-@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textRotate __attribute__((unavailable("Use textRotation instead.")));
+@property (nonatomic, null_resettable) NSExpression *textRotate __attribute__((unavailable("Use textRotation instead.")));
/**
In combination with `symbolPlacement`, determines the rotation behavior of the
individual glyphs forming the text.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLTextRotationAlignmentAuto`. Set this property
- to `nil` to reset it to the default value.
+ The default value of this property is an expression that evaluates to `auto`.
+ 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 instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant `MGLTextRotationAlignment` values
+ * Any of the following constant string values:
+ * `map`: When `symbol-placement` is set to `point`, aligns text east-west.
+ When `symbol-placement` is set to `line`, aligns text x-axes with the line.
+ * `viewport`: Produces glyphs whose x-axes are aligned with the x-axis of the
+ viewport, regardless of the value of `symbol-placement`.
+ * `auto`: When `symbol-placement` is set to `point`, this is equivalent to
+ `viewport`. When `symbol-placement` is set to `line`, this is equivalent to
+ `map`.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textRotationAlignment;
+@property (nonatomic, null_resettable) NSExpression *textRotationAlignment;
/**
Specifies how to capitalize text.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLTextTransformNone`. Set this property to `nil`
- to reset it to the default value.
+ The default value of this property is an expression that evaluates to `none`.
+ 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 instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ * Constant `MGLTextTransform` values
+ * Any of the following constant string values:
+ * `none`: The text is not altered.
+ * `uppercase`: Forces all letters to be displayed in uppercase.
+ * `lowercase`: Forces all letters to be displayed in lowercase.
+ * 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) MGLStyleValue<NSValue *> *textTransform;
+@property (nonatomic, null_resettable) NSExpression *textTransform;
#pragma mark - Accessing the Paint Attributes
@@ -1416,59 +1475,45 @@ MGL_EXPORT
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 `MGLStyleValue` object containing
+ The default value of this property is an expression that evaluates to
`UIColor.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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- */
-@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *iconColor;
+ You can set this property to an expression containing any of the following:
+
+ * Constant `UIColor` 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;
#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 `MGLStyleValue` object containing
+ 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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- */
-@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *iconColor;
+ 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
/**
@@ -1483,30 +1528,22 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
+ 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.
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ * Constant numeric values no less than 0
+ * 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) MGLStyleValue<NSNumber *> *iconHaloBlur;
+@property (nonatomic, null_resettable) NSExpression *iconHaloBlur;
/**
The transition affecting any changes to this layer’s `iconHaloBlur` property.
@@ -1520,59 +1557,45 @@ MGL_EXPORT
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 `MGLStyleValue` object containing
+ The default value of this property is an expression that evaluates to
`UIColor.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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- */
-@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *iconHaloColor;
+ You can set this property to an expression containing any of the following:
+
+ * Constant `UIColor` 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;
#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 `MGLStyleValue` object containing
+ 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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- */
-@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *iconHaloColor;
+ 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
/**
@@ -1587,30 +1610,22 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
+ 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.
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ * Constant numeric values no less than 0
+ * 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) MGLStyleValue<NSNumber *> *iconHaloWidth;
+@property (nonatomic, null_resettable) NSExpression *iconHaloWidth;
/**
The transition affecting any changes to this layer’s `iconHaloWidth` property.
@@ -1622,30 +1637,22 @@ MGL_EXPORT
/**
The opacity at which the icon will be drawn.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `1`. Set this property to `nil` to reset
- it to the default value.
+ 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.
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ * Constant numeric values between 0 and 1 inclusive
+ * 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) MGLStyleValue<NSNumber *> *iconOpacity;
+@property (nonatomic, null_resettable) NSExpression *iconOpacity;
/**
The transition affecting any changes to this layer’s `iconOpacity` property.
@@ -1660,7 +1667,7 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points downward. Set this property to `nil` to reset it to the default value.
@@ -1671,21 +1678,25 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-icon-translate"><code>icon-translate</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant `CGVector` 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslation;
+@property (nonatomic, null_resettable) NSExpression *iconTranslation;
#else
/**
Distance that the icon's anchor is moved from its original placement.
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points upward. Set this property to `nil` to reset it to the default value.
@@ -1696,14 +1707,18 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-icon-translate"><code>icon-translate</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ * Constant `CGVector` 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) MGLStyleValue<NSValue *> *iconTranslation;
+@property (nonatomic, null_resettable) NSExpression *iconTranslation;
#endif
/**
@@ -1713,14 +1728,13 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition iconTranslationTransition;
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslate __attribute__((unavailable("Use iconTranslation instead.")));
+@property (nonatomic, null_resettable) NSExpression *iconTranslate __attribute__((unavailable("Use iconTranslation instead.")));
/**
- Controls the translation reference point.
+ Controls the frame of reference for `iconTranslation`.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLIconTranslationAnchorMap`. Set this property to
- `nil` to reset it to the default value.
+ The default value of this property is an expression that evaluates to `map`.
+ 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`, and
`iconTranslation` is non-`nil`. Otherwise, it is ignored.
@@ -1729,72 +1743,67 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-icon-translate-anchor"><code>icon-translate-anchor</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant `MGLIconTranslationAnchor` values
+ * Any of the following constant string values:
+ * `map`: Icons are translated relative to the map.
+ * `viewport`: Icons are translated relative to the viewport.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslationAnchor;
+@property (nonatomic, null_resettable) NSExpression *iconTranslationAnchor;
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslateAnchor __attribute__((unavailable("Use iconTranslationAnchor instead.")));
+@property (nonatomic, null_resettable) NSExpression *iconTranslateAnchor __attribute__((unavailable("Use iconTranslationAnchor instead.")));
#if TARGET_OS_IPHONE
/**
The color with which the text will be drawn.
- The default value of this property is an `MGLStyleValue` object containing
+ The default value of this property is an expression that evaluates to
`UIColor.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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- */
-@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *textColor;
+ You can set this property to an expression containing any of the following:
+
+ * Constant `UIColor` 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;
#else
/**
The color with which the text will be drawn.
- The default value of this property is an `MGLStyleValue` object containing
+ 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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- */
-@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *textColor;
+ 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
/**
@@ -1809,30 +1818,22 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
+ 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.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ * Constant numeric values no less than 0
+ * 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) MGLStyleValue<NSNumber *> *textHaloBlur;
+@property (nonatomic, null_resettable) NSExpression *textHaloBlur;
/**
The transition affecting any changes to this layer’s `textHaloBlur` property.
@@ -1845,58 +1846,44 @@ MGL_EXPORT
/**
The color of the text's halo, which helps it stand out from backgrounds.
- The default value of this property is an `MGLStyleValue` object containing
+ The default value of this property is an expression that evaluates to
`UIColor.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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- */
-@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *textHaloColor;
+ You can set this property to an expression containing any of the following:
+
+ * Constant `UIColor` 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;
#else
/**
The color of the text's halo, which helps it stand out from backgrounds.
- The default value of this property is an `MGLStyleValue` object containing
+ 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 instance of:
-
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- */
-@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *textHaloColor;
+ 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
/**
@@ -1912,30 +1899,22 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `0`. Set this property to `nil` to reset
- it to the default value.
+ 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.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ * Constant numeric values no less than 0
+ * 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) MGLStyleValue<NSNumber *> *textHaloWidth;
+@property (nonatomic, null_resettable) NSExpression *textHaloWidth;
/**
The transition affecting any changes to this layer’s `textHaloWidth` property.
@@ -1947,30 +1926,22 @@ MGL_EXPORT
/**
The opacity at which the text will be drawn.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSNumber` object containing the float `1`. Set this property to `nil` to reset
- it to the default value.
+ 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.
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLSourceStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
- * `MGLInterpolationModeIdentity`
- * `MGLCompositeStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
- * `MGLInterpolationModeCategorical`
+ * Constant numeric values between 0 and 1 inclusive
+ * 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) MGLStyleValue<NSNumber *> *textOpacity;
+@property (nonatomic, null_resettable) NSExpression *textOpacity;
/**
The transition affecting any changes to this layer’s `textOpacity` property.
@@ -1985,7 +1956,7 @@ MGL_EXPORT
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points downward. Set this property to `nil` to reset it to the default value.
@@ -1996,21 +1967,25 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-text-translate"><code>text-translate</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant `CGVector` 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
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ This property does not support applying interpolation or step functions to
+ feature attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTranslation;
+@property (nonatomic, null_resettable) NSExpression *textTranslation;
#else
/**
Distance that the text's anchor is moved from its original placement.
This property is measured in points.
- The default value of this property is an `MGLStyleValue` object containing an
+ The default value of this property is an expression that evaluates to an
`NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
points upward. Set this property to `nil` to reset it to the default value.
@@ -2021,14 +1996,18 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-text-translate"><code>text-translate</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of:
- * `MGLInterpolationModeExponential`
- * `MGLInterpolationModeInterval`
+ * Constant `CGVector` 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) MGLStyleValue<NSValue *> *textTranslation;
+@property (nonatomic, null_resettable) NSExpression *textTranslation;
#endif
/**
@@ -2038,14 +2017,13 @@ MGL_EXPORT
*/
@property (nonatomic) MGLTransition textTranslationTransition;
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTranslate __attribute__((unavailable("Use textTranslation instead.")));
+@property (nonatomic, null_resettable) NSExpression *textTranslate __attribute__((unavailable("Use textTranslation instead.")));
/**
- Controls the translation reference point.
+ Controls the frame of reference for `textTranslation`.
- The default value of this property is an `MGLStyleValue` object containing an
- `NSValue` object containing `MGLTextTranslationAnchorMap`. Set this property to
- `nil` to reset it to the default value.
+ The default value of this property is an expression that evaluates to `map`.
+ 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
`textTranslation` is non-`nil`. Otherwise, it is ignored.
@@ -2054,15 +2032,24 @@ MGL_EXPORT
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-text-translate-anchor"><code>text-translate-anchor</code></a>
layout property in the Mapbox Style Specification.
- You can set this property to an instance of:
+ You can set this property to an expression containing any of the following:
+
+ * Constant `MGLTextTranslationAnchor` values
+ * Any of the following constant string values:
+ * `map`: The text is translated relative to the map.
+ * `viewport`: The text is translated relative to the viewport.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
- * `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
*/
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTranslationAnchor;
+@property (nonatomic, null_resettable) NSExpression *textTranslationAnchor;
-@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTranslateAnchor __attribute__((unavailable("Use textTranslationAnchor instead.")));
+@property (nonatomic, null_resettable) NSExpression *textTranslateAnchor __attribute__((unavailable("Use textTranslationAnchor instead.")));
@end
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.mm b/platform/darwin/src/MGLSymbolStyleLayer.mm
index 1990c82669..0d9fac4808 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.mm
+++ b/platform/darwin/src/MGLSymbolStyleLayer.mm
@@ -154,754 +154,756 @@ namespace mbgl {
#pragma mark - Accessing the Layout Attributes
-- (void)setIconAllowsOverlap:(MGLStyleValue<NSNumber *> *)iconAllowsOverlap {
+- (void)setIconAllowsOverlap:(NSExpression *)iconAllowsOverlap {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(iconAllowsOverlap);
+ auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<bool>>(iconAllowsOverlap);
self.rawLayer->setIconAllowOverlap(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)iconAllowsOverlap {
+- (NSExpression *)iconAllowsOverlap {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconAllowOverlap();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultIconAllowOverlap());
+ propertyValue = self.rawLayer->getDefaultIconAllowOverlap();
}
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<bool, NSNumber *>().toExpression(propertyValue);
}
-- (void)setIconAllowOverlap:(MGLStyleValue<NSNumber *> *)iconAllowOverlap {
+- (void)setIconAllowOverlap:(NSExpression *)iconAllowOverlap {
}
-- (MGLStyleValue<NSNumber *> *)iconAllowOverlap {
+- (NSExpression *)iconAllowOverlap {
return self.iconAllowsOverlap;
}
-- (void)setIconAnchor:(MGLStyleValue<NSValue *> *)iconAnchor {
+- (void)setIconAnchor:(NSExpression *)iconAnchor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLIconAnchor>().toDataDrivenPropertyValue(iconAnchor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLIconAnchor>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<mbgl::style::SymbolAnchorType>>(iconAnchor);
self.rawLayer->setIconAnchor(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)iconAnchor {
+- (NSExpression *)iconAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconAnchor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLIconAnchor>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconAnchor());
+ propertyValue = self.rawLayer->getDefaultIconAnchor();
}
- return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLIconAnchor>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLIconAnchor>().toExpression(propertyValue);
}
-- (void)setIconIgnoresPlacement:(MGLStyleValue<NSNumber *> *)iconIgnoresPlacement {
+- (void)setIconIgnoresPlacement:(NSExpression *)iconIgnoresPlacement {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(iconIgnoresPlacement);
+ auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<bool>>(iconIgnoresPlacement);
self.rawLayer->setIconIgnorePlacement(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)iconIgnoresPlacement {
+- (NSExpression *)iconIgnoresPlacement {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconIgnorePlacement();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultIconIgnorePlacement());
+ propertyValue = self.rawLayer->getDefaultIconIgnorePlacement();
}
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<bool, NSNumber *>().toExpression(propertyValue);
}
-- (void)setIconIgnorePlacement:(MGLStyleValue<NSNumber *> *)iconIgnorePlacement {
+- (void)setIconIgnorePlacement:(NSExpression *)iconIgnorePlacement {
}
-- (MGLStyleValue<NSNumber *> *)iconIgnorePlacement {
+- (NSExpression *)iconIgnorePlacement {
return self.iconIgnoresPlacement;
}
-- (void)setIconImageName:(MGLStyleValue<NSString *> *)iconImageName {
+- (void)setIconImageName:(NSExpression *)iconImageName {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toDataDrivenPropertyValue(iconImageName);
+ auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<std::string>>(iconImageName);
self.rawLayer->setIconImage(mbglValue);
}
-- (MGLStyleValue<NSString *> *)iconImageName {
+- (NSExpression *)iconImageName {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconImage();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::string, NSString *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconImage());
+ propertyValue = self.rawLayer->getDefaultIconImage();
}
- return MGLStyleValueTransformer<std::string, NSString *>().toDataDrivenStyleValue(propertyValue);
+ NSExpression *expression = MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ return expression.mgl_expressionByReplacingTokensWithKeyPaths;
}
-- (void)setIconImage:(MGLStyleValue<NSString *> *)iconImage {
+- (void)setIconImage:(NSExpression *)iconImage {
}
-- (MGLStyleValue<NSString *> *)iconImage {
+- (NSExpression *)iconImage {
return self.iconImageName;
}
-- (void)setIconOffset:(MGLStyleValue<NSValue *> *)iconOffset {
+- (void)setIconOffset:(NSExpression *)iconOffset {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toDataDrivenPropertyValue(iconOffset);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<std::array<float, 2>>>(iconOffset);
self.rawLayer->setIconOffset(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)iconOffset {
+- (NSExpression *)iconOffset {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconOffset();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconOffset());
+ propertyValue = self.rawLayer->getDefaultIconOffset();
}
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toExpression(propertyValue);
}
-- (void)setIconOptional:(MGLStyleValue<NSNumber *> *)iconOptional {
+- (void)setIconOptional:(NSExpression *)iconOptional {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(iconOptional);
+ auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<bool>>(iconOptional);
self.rawLayer->setIconOptional(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)isIconOptional {
+- (NSExpression *)isIconOptional {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconOptional();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultIconOptional());
+ propertyValue = self.rawLayer->getDefaultIconOptional();
}
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<bool, NSNumber *>().toExpression(propertyValue);
}
-- (void)setIconPadding:(MGLStyleValue<NSNumber *> *)iconPadding {
+- (void)setIconPadding:(NSExpression *)iconPadding {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(iconPadding);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(iconPadding);
self.rawLayer->setIconPadding(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)iconPadding {
+- (NSExpression *)iconPadding {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconPadding();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultIconPadding());
+ propertyValue = self.rawLayer->getDefaultIconPadding();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
-- (void)setIconPitchAlignment:(MGLStyleValue<NSValue *> *)iconPitchAlignment {
+- (void)setIconPitchAlignment:(NSExpression *)iconPitchAlignment {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconPitchAlignment>().toEnumPropertyValue(iconPitchAlignment);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconPitchAlignment>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::AlignmentType>>(iconPitchAlignment);
self.rawLayer->setIconPitchAlignment(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)iconPitchAlignment {
+- (NSExpression *)iconPitchAlignment {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconPitchAlignment();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconPitchAlignment>().toEnumStyleValue(self.rawLayer->getDefaultIconPitchAlignment());
+ propertyValue = self.rawLayer->getDefaultIconPitchAlignment();
}
- return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconPitchAlignment>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconPitchAlignment>().toExpression(propertyValue);
}
-- (void)setIconRotation:(MGLStyleValue<NSNumber *> *)iconRotation {
+- (void)setIconRotation:(NSExpression *)iconRotation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(iconRotation);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(iconRotation);
self.rawLayer->setIconRotate(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)iconRotation {
+- (NSExpression *)iconRotation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconRotate();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconRotate());
+ propertyValue = self.rawLayer->getDefaultIconRotate();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
-- (void)setIconRotate:(MGLStyleValue<NSNumber *> *)iconRotate {
+- (void)setIconRotate:(NSExpression *)iconRotate {
}
-- (MGLStyleValue<NSNumber *> *)iconRotate {
+- (NSExpression *)iconRotate {
return self.iconRotation;
}
-- (void)setIconRotationAlignment:(MGLStyleValue<NSValue *> *)iconRotationAlignment {
+- (void)setIconRotationAlignment:(NSExpression *)iconRotationAlignment {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconRotationAlignment>().toEnumPropertyValue(iconRotationAlignment);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconRotationAlignment>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::AlignmentType>>(iconRotationAlignment);
self.rawLayer->setIconRotationAlignment(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)iconRotationAlignment {
+- (NSExpression *)iconRotationAlignment {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconRotationAlignment();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconRotationAlignment>().toEnumStyleValue(self.rawLayer->getDefaultIconRotationAlignment());
+ propertyValue = self.rawLayer->getDefaultIconRotationAlignment();
}
- return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconRotationAlignment>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconRotationAlignment>().toExpression(propertyValue);
}
-- (void)setIconScale:(MGLStyleValue<NSNumber *> *)iconScale {
+- (void)setIconScale:(NSExpression *)iconScale {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(iconScale);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(iconScale);
self.rawLayer->setIconSize(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)iconScale {
+- (NSExpression *)iconScale {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconSize();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconSize());
+ propertyValue = self.rawLayer->getDefaultIconSize();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
-- (void)setIconSize:(MGLStyleValue<NSNumber *> *)iconSize {
+- (void)setIconSize:(NSExpression *)iconSize {
}
-- (MGLStyleValue<NSNumber *> *)iconSize {
+- (NSExpression *)iconSize {
return self.iconScale;
}
-- (void)setIconTextFit:(MGLStyleValue<NSValue *> *)iconTextFit {
+- (void)setIconTextFit:(NSExpression *)iconTextFit {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::IconTextFitType, NSValue *, mbgl::style::IconTextFitType, MGLIconTextFit>().toEnumPropertyValue(iconTextFit);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::IconTextFitType, NSValue *, mbgl::style::IconTextFitType, MGLIconTextFit>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::IconTextFitType>>(iconTextFit);
self.rawLayer->setIconTextFit(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)iconTextFit {
+- (NSExpression *)iconTextFit {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconTextFit();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::IconTextFitType, NSValue *, mbgl::style::IconTextFitType, MGLIconTextFit>().toEnumStyleValue(self.rawLayer->getDefaultIconTextFit());
+ propertyValue = self.rawLayer->getDefaultIconTextFit();
}
- return MGLStyleValueTransformer<mbgl::style::IconTextFitType, NSValue *, mbgl::style::IconTextFitType, MGLIconTextFit>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::IconTextFitType, NSValue *, mbgl::style::IconTextFitType, MGLIconTextFit>().toExpression(propertyValue);
}
-- (void)setIconTextFitPadding:(MGLStyleValue<NSValue *> *)iconTextFitPadding {
+- (void)setIconTextFitPadding:(NSExpression *)iconTextFitPadding {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 4>, NSValue *>().toInterpolatablePropertyValue(iconTextFitPadding);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 4>, NSValue *>().toPropertyValue<mbgl::style::PropertyValue<std::array<float, 4>>>(iconTextFitPadding);
self.rawLayer->setIconTextFitPadding(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)iconTextFitPadding {
+- (NSExpression *)iconTextFitPadding {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconTextFitPadding();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::array<float, 4>, NSValue *>().toStyleValue(self.rawLayer->getDefaultIconTextFitPadding());
+ propertyValue = self.rawLayer->getDefaultIconTextFitPadding();
}
- return MGLStyleValueTransformer<std::array<float, 4>, NSValue *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<std::array<float, 4>, NSValue *>().toExpression(propertyValue);
}
-- (void)setKeepsIconUpright:(MGLStyleValue<NSNumber *> *)keepsIconUpright {
+- (void)setKeepsIconUpright:(NSExpression *)keepsIconUpright {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(keepsIconUpright);
+ auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<bool>>(keepsIconUpright);
self.rawLayer->setIconKeepUpright(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)keepsIconUpright {
+- (NSExpression *)keepsIconUpright {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconKeepUpright();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultIconKeepUpright());
+ propertyValue = self.rawLayer->getDefaultIconKeepUpright();
}
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<bool, NSNumber *>().toExpression(propertyValue);
}
-- (void)setIconKeepUpright:(MGLStyleValue<NSNumber *> *)iconKeepUpright {
+- (void)setIconKeepUpright:(NSExpression *)iconKeepUpright {
}
-- (MGLStyleValue<NSNumber *> *)iconKeepUpright {
+- (NSExpression *)iconKeepUpright {
return self.keepsIconUpright;
}
-- (void)setKeepsTextUpright:(MGLStyleValue<NSNumber *> *)keepsTextUpright {
+- (void)setKeepsTextUpright:(NSExpression *)keepsTextUpright {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(keepsTextUpright);
+ auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<bool>>(keepsTextUpright);
self.rawLayer->setTextKeepUpright(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)keepsTextUpright {
+- (NSExpression *)keepsTextUpright {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextKeepUpright();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextKeepUpright());
+ propertyValue = self.rawLayer->getDefaultTextKeepUpright();
}
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<bool, NSNumber *>().toExpression(propertyValue);
}
-- (void)setTextKeepUpright:(MGLStyleValue<NSNumber *> *)textKeepUpright {
+- (void)setTextKeepUpright:(NSExpression *)textKeepUpright {
}
-- (MGLStyleValue<NSNumber *> *)textKeepUpright {
+- (NSExpression *)textKeepUpright {
return self.keepsTextUpright;
}
-- (void)setMaximumTextAngle:(MGLStyleValue<NSNumber *> *)maximumTextAngle {
+- (void)setMaximumTextAngle:(NSExpression *)maximumTextAngle {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(maximumTextAngle);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(maximumTextAngle);
self.rawLayer->setTextMaxAngle(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)maximumTextAngle {
+- (NSExpression *)maximumTextAngle {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextMaxAngle();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextMaxAngle());
+ propertyValue = self.rawLayer->getDefaultTextMaxAngle();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
-- (void)setTextMaxAngle:(MGLStyleValue<NSNumber *> *)textMaxAngle {
+- (void)setTextMaxAngle:(NSExpression *)textMaxAngle {
}
-- (MGLStyleValue<NSNumber *> *)textMaxAngle {
+- (NSExpression *)textMaxAngle {
return self.maximumTextAngle;
}
-- (void)setMaximumTextWidth:(MGLStyleValue<NSNumber *> *)maximumTextWidth {
+- (void)setMaximumTextWidth:(NSExpression *)maximumTextWidth {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(maximumTextWidth);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(maximumTextWidth);
self.rawLayer->setTextMaxWidth(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)maximumTextWidth {
+- (NSExpression *)maximumTextWidth {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextMaxWidth();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextMaxWidth());
+ propertyValue = self.rawLayer->getDefaultTextMaxWidth();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
-- (void)setTextMaxWidth:(MGLStyleValue<NSNumber *> *)textMaxWidth {
+- (void)setTextMaxWidth:(NSExpression *)textMaxWidth {
}
-- (MGLStyleValue<NSNumber *> *)textMaxWidth {
+- (NSExpression *)textMaxWidth {
return self.maximumTextWidth;
}
-- (void)setSymbolAvoidsEdges:(MGLStyleValue<NSNumber *> *)symbolAvoidsEdges {
+- (void)setSymbolAvoidsEdges:(NSExpression *)symbolAvoidsEdges {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(symbolAvoidsEdges);
+ auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<bool>>(symbolAvoidsEdges);
self.rawLayer->setSymbolAvoidEdges(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)symbolAvoidsEdges {
+- (NSExpression *)symbolAvoidsEdges {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getSymbolAvoidEdges();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultSymbolAvoidEdges());
+ propertyValue = self.rawLayer->getDefaultSymbolAvoidEdges();
}
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<bool, NSNumber *>().toExpression(propertyValue);
}
-- (void)setSymbolAvoidEdges:(MGLStyleValue<NSNumber *> *)symbolAvoidEdges {
+- (void)setSymbolAvoidEdges:(NSExpression *)symbolAvoidEdges {
}
-- (MGLStyleValue<NSNumber *> *)symbolAvoidEdges {
+- (NSExpression *)symbolAvoidEdges {
return self.symbolAvoidsEdges;
}
-- (void)setSymbolPlacement:(MGLStyleValue<NSValue *> *)symbolPlacement {
+- (void)setSymbolPlacement:(NSExpression *)symbolPlacement {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::SymbolPlacementType, NSValue *, mbgl::style::SymbolPlacementType, MGLSymbolPlacement>().toEnumPropertyValue(symbolPlacement);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::SymbolPlacementType, NSValue *, mbgl::style::SymbolPlacementType, MGLSymbolPlacement>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::SymbolPlacementType>>(symbolPlacement);
self.rawLayer->setSymbolPlacement(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)symbolPlacement {
+- (NSExpression *)symbolPlacement {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getSymbolPlacement();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::SymbolPlacementType, NSValue *, mbgl::style::SymbolPlacementType, MGLSymbolPlacement>().toEnumStyleValue(self.rawLayer->getDefaultSymbolPlacement());
+ propertyValue = self.rawLayer->getDefaultSymbolPlacement();
}
- return MGLStyleValueTransformer<mbgl::style::SymbolPlacementType, NSValue *, mbgl::style::SymbolPlacementType, MGLSymbolPlacement>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::SymbolPlacementType, NSValue *, mbgl::style::SymbolPlacementType, MGLSymbolPlacement>().toExpression(propertyValue);
}
-- (void)setSymbolSpacing:(MGLStyleValue<NSNumber *> *)symbolSpacing {
+- (void)setSymbolSpacing:(NSExpression *)symbolSpacing {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(symbolSpacing);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(symbolSpacing);
self.rawLayer->setSymbolSpacing(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)symbolSpacing {
+- (NSExpression *)symbolSpacing {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getSymbolSpacing();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultSymbolSpacing());
+ propertyValue = self.rawLayer->getDefaultSymbolSpacing();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
-- (void)setText:(MGLStyleValue<NSString *> *)text {
+- (void)setText:(NSExpression *)text {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toDataDrivenPropertyValue(text);
+ auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<std::string>>(text);
self.rawLayer->setTextField(mbglValue);
}
-- (MGLStyleValue<NSString *> *)text {
+- (NSExpression *)text {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextField();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::string, NSString *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextField());
+ propertyValue = self.rawLayer->getDefaultTextField();
}
- return MGLStyleValueTransformer<std::string, NSString *>().toDataDrivenStyleValue(propertyValue);
+ NSExpression *expression = MGLStyleValueTransformer<std::string, NSString *>().toExpression(propertyValue);
+ return expression.mgl_expressionByReplacingTokensWithKeyPaths;
}
-- (void)setTextField:(MGLStyleValue<NSString *> *)textField {
+- (void)setTextField:(NSExpression *)textField {
}
-- (MGLStyleValue<NSString *> *)textField {
+- (NSExpression *)textField {
return self.text;
}
-- (void)setTextAllowsOverlap:(MGLStyleValue<NSNumber *> *)textAllowsOverlap {
+- (void)setTextAllowsOverlap:(NSExpression *)textAllowsOverlap {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(textAllowsOverlap);
+ auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<bool>>(textAllowsOverlap);
self.rawLayer->setTextAllowOverlap(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)textAllowsOverlap {
+- (NSExpression *)textAllowsOverlap {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextAllowOverlap();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextAllowOverlap());
+ propertyValue = self.rawLayer->getDefaultTextAllowOverlap();
}
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<bool, NSNumber *>().toExpression(propertyValue);
}
-- (void)setTextAllowOverlap:(MGLStyleValue<NSNumber *> *)textAllowOverlap {
+- (void)setTextAllowOverlap:(NSExpression *)textAllowOverlap {
}
-- (MGLStyleValue<NSNumber *> *)textAllowOverlap {
+- (NSExpression *)textAllowOverlap {
return self.textAllowsOverlap;
}
-- (void)setTextAnchor:(MGLStyleValue<NSValue *> *)textAnchor {
+- (void)setTextAnchor:(NSExpression *)textAnchor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toDataDrivenPropertyValue(textAnchor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<mbgl::style::SymbolAnchorType>>(textAnchor);
self.rawLayer->setTextAnchor(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)textAnchor {
+- (NSExpression *)textAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextAnchor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextAnchor());
+ propertyValue = self.rawLayer->getDefaultTextAnchor();
}
- return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toExpression(propertyValue);
}
-- (void)setTextFontNames:(MGLStyleValue<NSArray<NSString *> *> *)textFontNames {
+- (void)setTextFontNames:(NSExpression *)textFontNames {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::vector<std::string>, NSArray<NSString *> *, std::string>().toPropertyValue(textFontNames);
+ auto mbglValue = MGLStyleValueTransformer<std::vector<std::string>, NSArray<NSString *> *, std::string>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<std::vector<std::string>>>(textFontNames);
self.rawLayer->setTextFont(mbglValue);
}
-- (MGLStyleValue<NSArray<NSString *> *> *)textFontNames {
+- (NSExpression *)textFontNames {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextFont();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::vector<std::string>, NSArray<NSString *> *, std::string>().toStyleValue(self.rawLayer->getDefaultTextFont());
+ propertyValue = self.rawLayer->getDefaultTextFont();
}
- return MGLStyleValueTransformer<std::vector<std::string>, NSArray<NSString *> *, std::string>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<std::vector<std::string>, NSArray<NSString *> *, std::string>().toExpression(propertyValue);
}
-- (void)setTextFont:(MGLStyleValue<NSArray<NSString *> *> *)textFont {
+- (void)setTextFont:(NSExpression *)textFont {
}
-- (MGLStyleValue<NSArray<NSString *> *> *)textFont {
+- (NSExpression *)textFont {
return self.textFontNames;
}
-- (void)setTextFontSize:(MGLStyleValue<NSNumber *> *)textFontSize {
+- (void)setTextFontSize:(NSExpression *)textFontSize {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(textFontSize);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(textFontSize);
self.rawLayer->setTextSize(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)textFontSize {
+- (NSExpression *)textFontSize {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextSize();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextSize());
+ propertyValue = self.rawLayer->getDefaultTextSize();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
-- (void)setTextSize:(MGLStyleValue<NSNumber *> *)textSize {
+- (void)setTextSize:(NSExpression *)textSize {
}
-- (MGLStyleValue<NSNumber *> *)textSize {
+- (NSExpression *)textSize {
return self.textFontSize;
}
-- (void)setTextIgnoresPlacement:(MGLStyleValue<NSNumber *> *)textIgnoresPlacement {
+- (void)setTextIgnoresPlacement:(NSExpression *)textIgnoresPlacement {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(textIgnoresPlacement);
+ auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<bool>>(textIgnoresPlacement);
self.rawLayer->setTextIgnorePlacement(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)textIgnoresPlacement {
+- (NSExpression *)textIgnoresPlacement {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextIgnorePlacement();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextIgnorePlacement());
+ propertyValue = self.rawLayer->getDefaultTextIgnorePlacement();
}
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<bool, NSNumber *>().toExpression(propertyValue);
}
-- (void)setTextIgnorePlacement:(MGLStyleValue<NSNumber *> *)textIgnorePlacement {
+- (void)setTextIgnorePlacement:(NSExpression *)textIgnorePlacement {
}
-- (MGLStyleValue<NSNumber *> *)textIgnorePlacement {
+- (NSExpression *)textIgnorePlacement {
return self.textIgnoresPlacement;
}
-- (void)setTextJustification:(MGLStyleValue<NSValue *> *)textJustification {
+- (void)setTextJustification:(NSExpression *)textJustification {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toDataDrivenPropertyValue(textJustification);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<mbgl::style::TextJustifyType>>(textJustification);
self.rawLayer->setTextJustify(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)textJustification {
+- (NSExpression *)textJustification {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextJustify();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextJustify());
+ propertyValue = self.rawLayer->getDefaultTextJustify();
}
- return MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toExpression(propertyValue);
}
-- (void)setTextJustify:(MGLStyleValue<NSValue *> *)textJustify {
+- (void)setTextJustify:(NSExpression *)textJustify {
}
-- (MGLStyleValue<NSValue *> *)textJustify {
+- (NSExpression *)textJustify {
return self.textJustification;
}
-- (void)setTextLetterSpacing:(MGLStyleValue<NSNumber *> *)textLetterSpacing {
+- (void)setTextLetterSpacing:(NSExpression *)textLetterSpacing {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(textLetterSpacing);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(textLetterSpacing);
self.rawLayer->setTextLetterSpacing(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)textLetterSpacing {
+- (NSExpression *)textLetterSpacing {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextLetterSpacing();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextLetterSpacing());
+ propertyValue = self.rawLayer->getDefaultTextLetterSpacing();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
-- (void)setTextLineHeight:(MGLStyleValue<NSNumber *> *)textLineHeight {
+- (void)setTextLineHeight:(NSExpression *)textLineHeight {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(textLineHeight);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(textLineHeight);
self.rawLayer->setTextLineHeight(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)textLineHeight {
+- (NSExpression *)textLineHeight {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextLineHeight();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextLineHeight());
+ propertyValue = self.rawLayer->getDefaultTextLineHeight();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
-- (void)setTextOffset:(MGLStyleValue<NSValue *> *)textOffset {
+- (void)setTextOffset:(NSExpression *)textOffset {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toDataDrivenPropertyValue(textOffset);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<std::array<float, 2>>>(textOffset);
self.rawLayer->setTextOffset(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)textOffset {
+- (NSExpression *)textOffset {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextOffset();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextOffset());
+ propertyValue = self.rawLayer->getDefaultTextOffset();
}
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toExpression(propertyValue);
}
-- (void)setTextOptional:(MGLStyleValue<NSNumber *> *)textOptional {
+- (void)setTextOptional:(NSExpression *)textOptional {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(textOptional);
+ auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<bool>>(textOptional);
self.rawLayer->setTextOptional(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)isTextOptional {
+- (NSExpression *)isTextOptional {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextOptional();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextOptional());
+ propertyValue = self.rawLayer->getDefaultTextOptional();
}
- return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<bool, NSNumber *>().toExpression(propertyValue);
}
-- (void)setTextPadding:(MGLStyleValue<NSNumber *> *)textPadding {
+- (void)setTextPadding:(NSExpression *)textPadding {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(textPadding);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(textPadding);
self.rawLayer->setTextPadding(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)textPadding {
+- (NSExpression *)textPadding {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextPadding();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextPadding());
+ propertyValue = self.rawLayer->getDefaultTextPadding();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
-- (void)setTextPitchAlignment:(MGLStyleValue<NSValue *> *)textPitchAlignment {
+- (void)setTextPitchAlignment:(NSExpression *)textPitchAlignment {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextPitchAlignment>().toEnumPropertyValue(textPitchAlignment);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextPitchAlignment>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::AlignmentType>>(textPitchAlignment);
self.rawLayer->setTextPitchAlignment(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)textPitchAlignment {
+- (NSExpression *)textPitchAlignment {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextPitchAlignment();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextPitchAlignment>().toEnumStyleValue(self.rawLayer->getDefaultTextPitchAlignment());
+ propertyValue = self.rawLayer->getDefaultTextPitchAlignment();
}
- return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextPitchAlignment>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextPitchAlignment>().toExpression(propertyValue);
}
-- (void)setTextRotation:(MGLStyleValue<NSNumber *> *)textRotation {
+- (void)setTextRotation:(NSExpression *)textRotation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(textRotation);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(textRotation);
self.rawLayer->setTextRotate(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)textRotation {
+- (NSExpression *)textRotation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextRotate();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextRotate());
+ propertyValue = self.rawLayer->getDefaultTextRotate();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
-- (void)setTextRotate:(MGLStyleValue<NSNumber *> *)textRotate {
+- (void)setTextRotate:(NSExpression *)textRotate {
}
-- (MGLStyleValue<NSNumber *> *)textRotate {
+- (NSExpression *)textRotate {
return self.textRotation;
}
-- (void)setTextRotationAlignment:(MGLStyleValue<NSValue *> *)textRotationAlignment {
+- (void)setTextRotationAlignment:(NSExpression *)textRotationAlignment {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextRotationAlignment>().toEnumPropertyValue(textRotationAlignment);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextRotationAlignment>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::AlignmentType>>(textRotationAlignment);
self.rawLayer->setTextRotationAlignment(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)textRotationAlignment {
+- (NSExpression *)textRotationAlignment {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextRotationAlignment();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextRotationAlignment>().toEnumStyleValue(self.rawLayer->getDefaultTextRotationAlignment());
+ propertyValue = self.rawLayer->getDefaultTextRotationAlignment();
}
- return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextRotationAlignment>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextRotationAlignment>().toExpression(propertyValue);
}
-- (void)setTextTransform:(MGLStyleValue<NSValue *> *)textTransform {
+- (void)setTextTransform:(NSExpression *)textTransform {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::TextTransformType, NSValue *, mbgl::style::TextTransformType, MGLTextTransform>().toDataDrivenPropertyValue(textTransform);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::TextTransformType, NSValue *, mbgl::style::TextTransformType, MGLTextTransform>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<mbgl::style::TextTransformType>>(textTransform);
self.rawLayer->setTextTransform(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)textTransform {
+- (NSExpression *)textTransform {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextTransform();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::TextTransformType, NSValue *, mbgl::style::TextTransformType, MGLTextTransform>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextTransform());
+ propertyValue = self.rawLayer->getDefaultTextTransform();
}
- return MGLStyleValueTransformer<mbgl::style::TextTransformType, NSValue *, mbgl::style::TextTransformType, MGLTextTransform>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::TextTransformType, NSValue *, mbgl::style::TextTransformType, MGLTextTransform>().toExpression(propertyValue);
}
#pragma mark - Accessing the Paint Attributes
-- (void)setIconColor:(MGLStyleValue<MGLColor *> *)iconColor {
+- (void)setIconColor:(NSExpression *)iconColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(iconColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<mbgl::Color>>(iconColor);
self.rawLayer->setIconColor(mbglValue);
}
-- (MGLStyleValue<MGLColor *> *)iconColor {
+- (NSExpression *)iconColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconColor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconColor());
+ propertyValue = self.rawLayer->getDefaultIconColor();
}
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(propertyValue);
}
- (void)setIconColorTransition:(MGLTransition )transition {
@@ -922,21 +924,21 @@ namespace mbgl {
return transition;
}
-- (void)setIconHaloBlur:(MGLStyleValue<NSNumber *> *)iconHaloBlur {
+- (void)setIconHaloBlur:(NSExpression *)iconHaloBlur {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(iconHaloBlur);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(iconHaloBlur);
self.rawLayer->setIconHaloBlur(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)iconHaloBlur {
+- (NSExpression *)iconHaloBlur {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconHaloBlur();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconHaloBlur());
+ propertyValue = self.rawLayer->getDefaultIconHaloBlur();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setIconHaloBlurTransition:(MGLTransition )transition {
@@ -957,21 +959,21 @@ namespace mbgl {
return transition;
}
-- (void)setIconHaloColor:(MGLStyleValue<MGLColor *> *)iconHaloColor {
+- (void)setIconHaloColor:(NSExpression *)iconHaloColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(iconHaloColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<mbgl::Color>>(iconHaloColor);
self.rawLayer->setIconHaloColor(mbglValue);
}
-- (MGLStyleValue<MGLColor *> *)iconHaloColor {
+- (NSExpression *)iconHaloColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconHaloColor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconHaloColor());
+ propertyValue = self.rawLayer->getDefaultIconHaloColor();
}
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(propertyValue);
}
- (void)setIconHaloColorTransition:(MGLTransition )transition {
@@ -992,21 +994,21 @@ namespace mbgl {
return transition;
}
-- (void)setIconHaloWidth:(MGLStyleValue<NSNumber *> *)iconHaloWidth {
+- (void)setIconHaloWidth:(NSExpression *)iconHaloWidth {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(iconHaloWidth);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(iconHaloWidth);
self.rawLayer->setIconHaloWidth(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)iconHaloWidth {
+- (NSExpression *)iconHaloWidth {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconHaloWidth();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconHaloWidth());
+ propertyValue = self.rawLayer->getDefaultIconHaloWidth();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setIconHaloWidthTransition:(MGLTransition )transition {
@@ -1027,21 +1029,21 @@ namespace mbgl {
return transition;
}
-- (void)setIconOpacity:(MGLStyleValue<NSNumber *> *)iconOpacity {
+- (void)setIconOpacity:(NSExpression *)iconOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(iconOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(iconOpacity);
self.rawLayer->setIconOpacity(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)iconOpacity {
+- (NSExpression *)iconOpacity {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconOpacity();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconOpacity());
+ propertyValue = self.rawLayer->getDefaultIconOpacity();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setIconOpacityTransition:(MGLTransition )transition {
@@ -1062,21 +1064,21 @@ namespace mbgl {
return transition;
}
-- (void)setIconTranslation:(MGLStyleValue<NSValue *> *)iconTranslation {
+- (void)setIconTranslation:(NSExpression *)iconTranslation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toInterpolatablePropertyValue(iconTranslation);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue<mbgl::style::PropertyValue<std::array<float, 2>>>(iconTranslation);
self.rawLayer->setIconTranslate(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)iconTranslation {
+- (NSExpression *)iconTranslation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconTranslate();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(self.rawLayer->getDefaultIconTranslate());
+ propertyValue = self.rawLayer->getDefaultIconTranslate();
}
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toExpression(propertyValue);
}
- (void)setIconTranslationTransition:(MGLTransition )transition {
@@ -1097,52 +1099,52 @@ namespace mbgl {
return transition;
}
-- (void)setIconTranslate:(MGLStyleValue<NSValue *> *)iconTranslate {
+- (void)setIconTranslate:(NSExpression *)iconTranslate {
}
-- (MGLStyleValue<NSValue *> *)iconTranslate {
+- (NSExpression *)iconTranslate {
return self.iconTranslation;
}
-- (void)setIconTranslationAnchor:(MGLStyleValue<NSValue *> *)iconTranslationAnchor {
+- (void)setIconTranslationAnchor:(NSExpression *)iconTranslationAnchor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslationAnchor>().toEnumPropertyValue(iconTranslationAnchor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslationAnchor>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType>>(iconTranslationAnchor);
self.rawLayer->setIconTranslateAnchor(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)iconTranslationAnchor {
+- (NSExpression *)iconTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getIconTranslateAnchor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslationAnchor>().toEnumStyleValue(self.rawLayer->getDefaultIconTranslateAnchor());
+ propertyValue = self.rawLayer->getDefaultIconTranslateAnchor();
}
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslationAnchor>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslationAnchor>().toExpression(propertyValue);
}
-- (void)setIconTranslateAnchor:(MGLStyleValue<NSValue *> *)iconTranslateAnchor {
+- (void)setIconTranslateAnchor:(NSExpression *)iconTranslateAnchor {
}
-- (MGLStyleValue<NSValue *> *)iconTranslateAnchor {
+- (NSExpression *)iconTranslateAnchor {
return self.iconTranslationAnchor;
}
-- (void)setTextColor:(MGLStyleValue<MGLColor *> *)textColor {
+- (void)setTextColor:(NSExpression *)textColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(textColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<mbgl::Color>>(textColor);
self.rawLayer->setTextColor(mbglValue);
}
-- (MGLStyleValue<MGLColor *> *)textColor {
+- (NSExpression *)textColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextColor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextColor());
+ propertyValue = self.rawLayer->getDefaultTextColor();
}
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(propertyValue);
}
- (void)setTextColorTransition:(MGLTransition )transition {
@@ -1163,21 +1165,21 @@ namespace mbgl {
return transition;
}
-- (void)setTextHaloBlur:(MGLStyleValue<NSNumber *> *)textHaloBlur {
+- (void)setTextHaloBlur:(NSExpression *)textHaloBlur {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(textHaloBlur);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(textHaloBlur);
self.rawLayer->setTextHaloBlur(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)textHaloBlur {
+- (NSExpression *)textHaloBlur {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextHaloBlur();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextHaloBlur());
+ propertyValue = self.rawLayer->getDefaultTextHaloBlur();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setTextHaloBlurTransition:(MGLTransition )transition {
@@ -1198,21 +1200,21 @@ namespace mbgl {
return transition;
}
-- (void)setTextHaloColor:(MGLStyleValue<MGLColor *> *)textHaloColor {
+- (void)setTextHaloColor:(NSExpression *)textHaloColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(textHaloColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<mbgl::Color>>(textHaloColor);
self.rawLayer->setTextHaloColor(mbglValue);
}
-- (MGLStyleValue<MGLColor *> *)textHaloColor {
+- (NSExpression *)textHaloColor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextHaloColor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextHaloColor());
+ propertyValue = self.rawLayer->getDefaultTextHaloColor();
}
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toExpression(propertyValue);
}
- (void)setTextHaloColorTransition:(MGLTransition )transition {
@@ -1233,21 +1235,21 @@ namespace mbgl {
return transition;
}
-- (void)setTextHaloWidth:(MGLStyleValue<NSNumber *> *)textHaloWidth {
+- (void)setTextHaloWidth:(NSExpression *)textHaloWidth {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(textHaloWidth);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(textHaloWidth);
self.rawLayer->setTextHaloWidth(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)textHaloWidth {
+- (NSExpression *)textHaloWidth {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextHaloWidth();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextHaloWidth());
+ propertyValue = self.rawLayer->getDefaultTextHaloWidth();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setTextHaloWidthTransition:(MGLTransition )transition {
@@ -1268,21 +1270,21 @@ namespace mbgl {
return transition;
}
-- (void)setTextOpacity:(MGLStyleValue<NSNumber *> *)textOpacity {
+- (void)setTextOpacity:(NSExpression *)textOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(textOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<float>>(textOpacity);
self.rawLayer->setTextOpacity(mbglValue);
}
-- (MGLStyleValue<NSNumber *> *)textOpacity {
+- (NSExpression *)textOpacity {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextOpacity();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextOpacity());
+ propertyValue = self.rawLayer->getDefaultTextOpacity();
}
- return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
}
- (void)setTextOpacityTransition:(MGLTransition )transition {
@@ -1303,21 +1305,21 @@ namespace mbgl {
return transition;
}
-- (void)setTextTranslation:(MGLStyleValue<NSValue *> *)textTranslation {
+- (void)setTextTranslation:(NSExpression *)textTranslation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toInterpolatablePropertyValue(textTranslation);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue<mbgl::style::PropertyValue<std::array<float, 2>>>(textTranslation);
self.rawLayer->setTextTranslate(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)textTranslation {
+- (NSExpression *)textTranslation {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextTranslate();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(self.rawLayer->getDefaultTextTranslate());
+ propertyValue = self.rawLayer->getDefaultTextTranslate();
}
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toExpression(propertyValue);
}
- (void)setTextTranslationTransition:(MGLTransition )transition {
@@ -1338,34 +1340,34 @@ namespace mbgl {
return transition;
}
-- (void)setTextTranslate:(MGLStyleValue<NSValue *> *)textTranslate {
+- (void)setTextTranslate:(NSExpression *)textTranslate {
}
-- (MGLStyleValue<NSValue *> *)textTranslate {
+- (NSExpression *)textTranslate {
return self.textTranslation;
}
-- (void)setTextTranslationAnchor:(MGLStyleValue<NSValue *> *)textTranslationAnchor {
+- (void)setTextTranslationAnchor:(NSExpression *)textTranslationAnchor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslationAnchor>().toEnumPropertyValue(textTranslationAnchor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslationAnchor>().toPropertyValue<mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType>>(textTranslationAnchor);
self.rawLayer->setTextTranslateAnchor(mbglValue);
}
-- (MGLStyleValue<NSValue *> *)textTranslationAnchor {
+- (NSExpression *)textTranslationAnchor {
MGLAssertStyleLayerIsValid();
auto propertyValue = self.rawLayer->getTextTranslateAnchor();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslationAnchor>().toEnumStyleValue(self.rawLayer->getDefaultTextTranslateAnchor());
+ propertyValue = self.rawLayer->getDefaultTextTranslateAnchor();
}
- return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslationAnchor>().toEnumStyleValue(propertyValue);
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslationAnchor>().toExpression(propertyValue);
}
-- (void)setTextTranslateAnchor:(MGLStyleValue<NSValue *> *)textTranslateAnchor {
+- (void)setTextTranslateAnchor:(NSExpression *)textTranslateAnchor {
}
-- (MGLStyleValue<NSValue *> *)textTranslateAnchor {
+- (NSExpression *)textTranslateAnchor {
return self.textTranslationAnchor;
}
diff --git a/platform/darwin/src/MGLTileSource.h b/platform/darwin/src/MGLTileSource.h
index 3dc268db60..667e1e66ca 100644
--- a/platform/darwin/src/MGLTileSource.h
+++ b/platform/darwin/src/MGLTileSource.h
@@ -117,6 +117,7 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionInfos;
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem;
+
/**
Tile coordinate systems that determine how tile coordinates in tile URLs are
interpreted.
@@ -141,6 +142,35 @@ typedef NS_ENUM(NSUInteger, MGLTileCoordinateSystem) {
MGLTileCoordinateSystemTMS
};
+
+/**
+ 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 is not supported by the TileJSON spec.
+ */
+extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionDEMEncoding;
+
+/**
+ The encoding formula used to generate the raster-dem tileset
+*/
+
+typedef NS_ENUM(NSUInteger, MGLDEMEncoding) {
+
+ /**
+ Raster tiles generated with the [Mapbox encoding formula](https://www.mapbox.com/help/access-elevation-data/#mapbox-terrain-rgb).
+ */
+ MGLDEMEncodingMapbox = 0,
+
+ /**
+ Raster tiles generated with the [Mapzen Terrarium encoding formula](https://aws.amazon.com/public-datasets/terrain/).
+ */
+ MGLDEMEncodingTerrarium
+};
+
/**
`MGLTileSource` is a map content source that supplies map tiles to be shown on
the map. The location of and metadata about the tiles are defined either by an
@@ -154,9 +184,9 @@ typedef NS_ENUM(NSUInteger, MGLTileCoordinateSystem) {
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
@@ -182,7 +212,7 @@ MGL_EXPORT
configuration URL, this array is also empty until the configuration JSON file
is loaded.
*/
-@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLAttributionInfo *) *attributionInfos;
+@property (nonatomic, copy, readonly) NSArray<MGLAttributionInfo *> *attributionInfos;
@end
diff --git a/platform/darwin/src/MGLTileSource.mm b/platform/darwin/src/MGLTileSource.mm
index bc985bd728..2fafc6fb51 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"
@@ -19,6 +20,7 @@ const MGLTileSourceOption MGLTileSourceOptionCoordinateBounds = @"MGLTileSourceO
const MGLTileSourceOption MGLTileSourceOptionAttributionHTMLString = @"MGLTileSourceOptionAttributionHTMLString";
const MGLTileSourceOption MGLTileSourceOptionAttributionInfos = @"MGLTileSourceOptionAttributionInfos";
const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem = @"MGLTileSourceOptionTileCoordinateSystem";
+const MGLTileSourceOption MGLTileSourceOptionDEMEncoding = @"MGLTileSourceOptionDEMEncoding";
@implementation MGLTileSource
@@ -28,11 +30,11 @@ const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem = @"MGLTileSou
return nil;
}
-- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos {
+- (NSArray<MGLAttributionInfo *> *)attributionInfos {
return [self attributionInfosWithFontSize:0 linkColor:nil];
}
-- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
+- (NSArray<MGLAttributionInfo *> *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
return [MGLAttributionInfo attributionInfosFromHTMLString:self.attributionHTMLString
fontSize:fontSize
linkColor:linkColor];
@@ -46,7 +48,7 @@ const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem = @"MGLTileSou
@end
-mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTemplates, NS_DICTIONARY_OF(MGLTileSourceOption, id) * _Nullable options) {
+mbgl::Tileset MGLTileSetFromTileURLTemplates(NSArray<NSString *> *tileURLTemplates, NSDictionary<MGLTileSourceOption, id> * _Nullable options) {
mbgl::Tileset tileSet;
for (NSString *tileURLTemplate in tileURLTemplates) {
@@ -129,5 +131,22 @@ mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTem
}
}
+ if (NSNumber *demEncodingNumber = options[MGLTileSourceOptionDEMEncoding]) {
+ if (![demEncodingNumber isKindOfClass:[NSValue class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"MGLTileSourceOptionDEMEncoding must be set to an NSValue or NSNumber."];
+ }
+ MGLDEMEncoding demEncoding;
+ [demEncodingNumber getValue:&demEncoding];
+ switch (demEncoding) {
+ case MGLDEMEncodingMapbox:
+ tileSet.encoding = mbgl::Tileset::DEMEncoding::Mapbox;
+ break;
+ case MGLDEMEncodingTerrarium:
+ tileSet.encoding = mbgl::Tileset::DEMEncoding::Terrarium;
+ break;
+ }
+ }
+
return tileSet;
}
diff --git a/platform/darwin/src/MGLTileSource_Private.h b/platform/darwin/src/MGLTileSource_Private.h
index 0d9876d412..1b260ca86a 100644
--- a/platform/darwin/src/MGLTileSource_Private.h
+++ b/platform/darwin/src/MGLTileSource_Private.h
@@ -28,11 +28,11 @@ namespace mbgl {
@param fontSize The default text size in points, or 0 to use the default.
@param linkColor The default link color, or `nil` to use the default.
*/
-- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
+- (NSArray<MGLAttributionInfo *> *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
@end
MGL_EXPORT
-mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTemplates, NS_DICTIONARY_OF(MGLTileSourceOption, id) * _Nullable options);
+mbgl::Tileset MGLTileSetFromTileURLTemplates(NSArray<NSString *> *tileURLTemplates, NSDictionary<MGLTileSourceOption, id> * _Nullable options);
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLTypes.h b/platform/darwin/src/MGLTypes.h
index 5c32791c2f..fbc3a43ea2 100644
--- a/platform/darwin/src/MGLTypes.h
+++ b/platform/darwin/src/MGLTypes.h
@@ -111,23 +111,3 @@ NS_INLINE MGLTransition MGLTransitionMake(NSTimeInterval duration, NSTimeInterva
}
NS_ASSUME_NONNULL_END
-
-#ifndef NS_ARRAY_OF
- // Foundation collection classes adopted lightweight generics in iOS 9.0 and OS X 10.11 SDKs.
- #if __has_feature(objc_generics) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 90000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101100)
- /** Inserts a type specifier for a pointer to a lightweight generic with the given collection and object classes. Use a `*` for any non-`id` object classes but no `*` for the collection class. */
- #define NS_ARRAY_OF(ObjectClass...) NSArray <ObjectClass>
- #define NS_MUTABLE_ARRAY_OF(ObjectClass...) NSMutableArray <ObjectClass>
- #define NS_SET_OF(ObjectClass...) NSSet <ObjectClass>
- #define NS_MUTABLE_SET_OF(ObjectClass...) NSMutableSet <ObjectClass>
- #define NS_DICTIONARY_OF(ObjectClass...) NSDictionary <ObjectClass>
- #define NS_MUTABLE_DICTIONARY_OF(ObjectClass...) NSMutableDictionary <ObjectClass>
- #else
- #define NS_ARRAY_OF(ObjectClass...) NSArray
- #define NS_MUTABLE_ARRAY_OF(ObjectClass...) NSMutableArray
- #define NS_SET_OF(ObjectClass...) NSSet
- #define NS_MUTABLE_SET_OF(ObjectClass...) NSMutableSet
- #define NS_DICTIONARY_OF(ObjectClass...) NSDictionary
- #define NS_MUTABLE_DICTIONARY_OF(ObjectClass...) NSMutableDictionary
- #endif
-#endif
diff --git a/platform/darwin/src/MGLVectorSource+MGLAdditions.h b/platform/darwin/src/MGLVectorSource+MGLAdditions.h
deleted file mode 100644
index 43b0aba747..0000000000
--- a/platform/darwin/src/MGLVectorSource+MGLAdditions.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#import <Mapbox/Mapbox.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface MGLVectorSource (MGLAdditions)
-
-+ (NSString *)preferredMapboxStreetsLanguage;
-
-- (NS_DICTIONARY_OF(NSString *, NSString *) *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage;
-
-@property (nonatomic, readonly, getter=isMapboxStreets) BOOL mapboxStreets;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLVectorSource+MGLAdditions.m b/platform/darwin/src/MGLVectorSource+MGLAdditions.m
deleted file mode 100644
index a305388117..0000000000
--- a/platform/darwin/src/MGLVectorSource+MGLAdditions.m
+++ /dev/null
@@ -1,53 +0,0 @@
-#import "MGLVectorSource+MGLAdditions.h"
-
-@implementation MGLVectorSource (MGLAdditions)
-
-+ (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];
- });
- return mapboxStreetsLanguages;
-}
-
-+ (NSString *)preferredMapboxStreetsLanguage {
- NSArray<NSString *> *supportedLanguages = [MGLVectorSource mapboxStreetsLanguages].allObjects;
- NSArray<NSString *> *preferredLanguages = [NSBundle preferredLocalizationsFromArray:supportedLanguages
- forPreferences:[NSLocale preferredLanguages]];
- NSString *mostSpecificLanguage;
- for (NSString *language in preferredLanguages) {
- if (language.length > mostSpecificLanguage.length) {
- mostSpecificLanguage = language;
- }
- }
- return mostSpecificLanguage ?: @"en";
-}
-
-- (BOOL)isMapboxStreets {
- NSURL *url = self.configurationURL;
- if (![url.scheme isEqualToString:@"mapbox"]) {
- return NO;
- }
- NSArray *identifiers = [url.host componentsSeparatedByString:@","];
- return [identifiers containsObject:@"mapbox.mapbox-streets-v7"] || [identifiers containsObject:@"mapbox.mapbox-streets-v6"];
-}
-
-- (NS_DICTIONARY_OF(NSString *, NSString *) *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage {
- if (!self.mapboxStreets) {
- return @{};
- }
-
- // 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]) {
- NSString *key = [NSString stringWithFormat:@"name_%@", languageCode];
- localizedKeysByKey[key] = localizedKey;
- }
- return localizedKeysByKey;
-}
-
-@end
diff --git a/platform/darwin/src/MGLVectorSource.mm b/platform/darwin/src/MGLVectorSource.mm
deleted file mode 100644
index b1bda56f2d..0000000000
--- a/platform/darwin/src/MGLVectorSource.mm
+++ /dev/null
@@ -1,73 +0,0 @@
-#import "MGLVectorSource_Private.h"
-
-#import "MGLFeature_Private.h"
-#import "MGLSource_Private.h"
-#import "MGLTileSource_Private.h"
-#import "MGLStyle_Private.h"
-#import "MGLMapView_Private.h"
-#import "NSPredicate+MGLAdditions.h"
-#import "NSURL+MGLAdditions.h"
-
-#include <mbgl/map/map.hpp>
-#include <mbgl/style/sources/vector_source.hpp>
-#include <mbgl/renderer/renderer.hpp>
-
-@interface MGLVectorSource ()
-
-@property (nonatomic, readonly) mbgl::style::VectorSource *rawSource;
-
-@end
-
-@implementation MGLVectorSource
-
-- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL {
- auto source = std::make_unique<mbgl::style::VectorSource>(identifier.UTF8String,
- configurationURL.mgl_URLByStandardizingScheme.absoluteString.UTF8String);
- return self = [super initWithPendingSource:std::move(source)];
-}
-
-- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options {
- mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
- auto source = std::make_unique<mbgl::style::VectorSource>(identifier.UTF8String, tileSet);
- return self = [super initWithPendingSource:std::move(source)];
-}
-
-- (mbgl::style::VectorSource *)rawSource {
- return (mbgl::style::VectorSource *)super.rawSource;
-}
-
-- (NSURL *)configurationURL {
- auto url = self.rawSource->getURL();
- return url ? [NSURL URLWithString:@(url->c_str())] : nil;
-}
-
-- (NSString *)attributionHTMLString {
- auto attribution = self.rawSource->getAttribution();
- return attribution ? @(attribution->c_str()) : nil;
-}
-
-- (NS_ARRAY_OF(id <MGLFeature>) *)featuresInSourceLayersWithIdentifiers:(NS_SET_OF(NSString *) *)sourceLayerIdentifiers predicate:(nullable NSPredicate *)predicate {
-
- mbgl::optional<std::vector<std::string>> optionalSourceLayerIDs;
- if (sourceLayerIdentifiers) {
- __block std::vector<std::string> layerIDs;
- layerIDs.reserve(sourceLayerIdentifiers.count);
- [sourceLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop) {
- layerIDs.push_back(identifier.UTF8String);
- }];
- optionalSourceLayerIDs = layerIDs;
- }
-
- mbgl::optional<mbgl::style::Filter> optionalFilter;
- if (predicate) {
- optionalFilter = predicate.mgl_filter;
- }
-
- std::vector<mbgl::Feature> features;
- if (self.mapView) {
- features = self.mapView.renderer->querySourceFeatures(self.rawSource->getID(), { optionalSourceLayerIDs, optionalFilter });
- }
- return MGLFeaturesFromMBGLFeatures(features);
-}
-
-@end
diff --git a/platform/darwin/src/MGLVectorSource_Private.h b/platform/darwin/src/MGLVectorSource_Private.h
deleted file mode 100644
index 335743173e..0000000000
--- a/platform/darwin/src/MGLVectorSource_Private.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#import "MGLVectorSource.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface MGLVectorSource (Private)
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLVectorStyleLayer.h b/platform/darwin/src/MGLVectorStyleLayer.h
index 6603570e25..d9431215a1 100644
--- a/platform/darwin/src/MGLVectorStyleLayer.h
+++ b/platform/darwin/src/MGLVectorStyleLayer.h
@@ -7,13 +7,13 @@ 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`, `MGLLineStyleLayer`, and `MGLSymbolStyleLayer` in
- order to use `MGLVectorStyleLayer`'s properties and methods. Do not create
- instances of `MGLVectorStyleLayer` directly, and do not create your own
- subclasses of this class.
+ `MGLFillExtrusionStyleLayer`, `MGLHeatmapStyleLayer`, `MGLLineStyleLayer`, and
+ `MGLSymbolStyleLayer` in order to use `MGLVectorStyleLayer`'s properties and
+ methods. Do not create instances of `MGLVectorStyleLayer` directly, and do not
+ create your own subclasses of this class.
*/
MGL_EXPORT
@interface MGLVectorStyleLayer : MGLForegroundStyleLayer
@@ -34,108 +34,9 @@ MGL_EXPORT
comes from the style, its predicate corresponds to the
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#layer-filter">`filter`</a>
property in the style JSON.
-
- The following comparison operators are supported.
-
- <ul>
- <li><code>NSEqualToPredicateOperatorType</code> (<code>=</code>, <code>==</code>)</li>
- <li><code>NSGreaterThanOrEqualToPredicateOperatorType</code> (<code>>=</code>, <code>=></code>)</li>
- <li><code>NSLessThanOrEqualToPredicateOperatorType</code> (<code><=</code>, <code>=<</code>)</li>
- <li><code>NSGreaterThanPredicateOperatorType</code> (<code>></code>)</li>
- <li><code>NSLessThanPredicateOperatorType</code> (<code><</code>)</li>
- <li><code>NSNotEqualToPredicateOperatorType</code> (<code>!=</code>, <code><></code>)</li>
- <li><code>NSBetweenPredicateOperatorType</code> (<code>BETWEEN</code>)</li>
- </ul>
-
- The following compound operators are supported:
-
- <ul>
- <li><code>NSAndPredicateType</code> (<code>AND</code>, <code>&&</code>)</li>
- <li><code>NSOrPredicateType</code> (<code>OR</code>, <code>||</code>)</li>
- <li><code>NSNotPredicateType</code> (<code>NOT</code>, <code>!</code>)</li>
- </ul>
-
- The following aggregate operators are supported:
-
- <ul>
- <li><code>NSInPredicateOperatorType</code> (<code>IN</code>)</li>
- <li><code>NSContainsPredicateOperatorType</code> (<code>CONTAINS</code>)</li>
- </ul>
-
- To test whether a feature has or lacks a specific attribute, compare the
- attribute to `NULL` or `NIL`. Predicates created using the
- `+[NSPredicate predicateWithValue:]` method are also supported. String
- operators and custom operators are not supported.
-
- For details about the predicate format string syntax, consult the “Predicate
- Format String Syntax” chapter of the
- “<a href="https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Predicates/">Predicate Programming Guide</a>”
- in Apple developer documentation.
-
- The predicate's left-hand expression must be a string that identifies a feature
- attribute or, alternatively, one of the following special attributes:
-
- <table>
- <thead>
- <tr><th>Attribute</th><th>Meaning</th></tr>
- </thead>
- <tbody>
- <tr>
- <td><code>$id</code></td>
- <td>
- A value that uniquely identifies the feature in the containing source.
- For details on the types of values that may be associated with this key,
- consult the documentation for the <code>MGLFeature</code> protocol’s
- <code>identifier</code> property.
- </td>
- </tr>
- <tr>
- <td><code>$type</code></td>
- <td>
- The type of geometry represented by the feature. A feature’s type is
- guaranteed to be one of the following strings:
- <ul>
- <li>
- <code>Point</code> for point features, corresponding to the
- <code>MGLPointAnnotation</code> class
- </li>
- <li>
- <code>LineString</code> for polyline features, corresponding to
- the <code>MGLPolyline</code> class
- </li>
- <li>
- <code>Polygon</code> for polygon features, corresponding to the
- <code>MGLPolygon</code> class
- </li>
- </ul>
- </td>
- </tr>
- <tr>
- <td><code>point_count</code></td>
- <td>The number of point features in a given cluster.</td>
- </tr>
- </tbody>
- </table>
-
- The predicate’s right-hand expression must be an `NSString` (to match strings)
- or `NSNumber` (to match numbers, including Boolean values) or an array of
- `NSString`s or `NSNumber`s, depending on the operator and the type of values
- expected for the attribute being tested. For floating-point values, use
- `-[NSNumber numberWithDouble:]` instead of `-[NSNumber numberWithFloat:]`
- to avoid precision issues.
-
- Automatic type casting is not performed. Therefore, a feature only matches this
- predicate if its value for the attribute in question is of the same type as the
- value specified in the predicate. Also, operator modifiers such as `c` (for
- case insensitivity), `d` (for diacritic insensitivity), and `l` (for locale
- sensitivity) are unsupported for comparison and aggregate operators that are
- used in the predicate.
-
- It is possible to create expressions that contain special characters in the
- predicate format syntax. This includes the `$` in the `$id` and `$type` special
- style attributes and also `hyphen-minus` and `tag:subtag`. However, you must use
- `%K` in the format string to represent these variables:
- `@"%K == 'LineString'", @"$type"`.
+
+ See the “<a href="../predicates-and-expressions.html">Predicates and Expressions</a>”
+ guide for details about the predicate syntax supported by this class.
### Example
@@ -146,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..70d2f6e8ec 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
@@ -90,7 +99,7 @@ MGL_EXPORT
the default values.
@return An initialized tile source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NSArray<NSString *> *)tileURLTemplates options:(nullable NSDictionary<MGLTileSourceOption, id> *)options NS_DESIGNATED_INITIALIZER;
#pragma mark Accessing a Source’s Content
@@ -129,7 +138,7 @@ MGL_EXPORT
@return An array of objects conforming to the `MGLFeature` protocol that
represent features loaded by the source that match the predicate.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)featuresInSourceLayersWithIdentifiers:(NS_SET_OF(NSString *) *)sourceLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(features(sourceLayerIdentifiers:predicate:));
+- (NSArray<id <MGLFeature>> *)featuresInSourceLayersWithIdentifiers:(NSSet<NSString *> *)sourceLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(features(sourceLayerIdentifiers:predicate:));
@end
diff --git a/platform/darwin/src/MGLVectorTileSource.mm b/platform/darwin/src/MGLVectorTileSource.mm
new file mode 100644
index 0000000000..c6715d1759
--- /dev/null
+++ b/platform/darwin/src/MGLVectorTileSource.mm
@@ -0,0 +1,153 @@
+#import "MGLVectorTileSource_Private.h"
+
+#import "MGLFeature_Private.h"
+#import "MGLSource_Private.h"
+#import "MGLTileSource_Private.h"
+#import "MGLStyle_Private.h"
+#import "MGLMapView_Private.h"
+
+#import "NSPredicate+MGLAdditions.h"
+#import "NSURL+MGLAdditions.h"
+
+#include <mbgl/map/map.hpp>
+#include <mbgl/style/sources/vector_source.hpp>
+#include <mbgl/renderer/renderer.hpp>
+
+@interface MGLVectorTileSource ()
+
+@property (nonatomic, readonly) mbgl::style::VectorSource *rawSource;
+
+@end
+
+@implementation MGLVectorTileSource
+
+- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL {
+ auto source = std::make_unique<mbgl::style::VectorSource>(identifier.UTF8String,
+ configurationURL.mgl_URLByStandardizingScheme.absoluteString.UTF8String);
+ return self = [super initWithPendingSource:std::move(source)];
+}
+
+- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NSArray<NSString *> *)tileURLTemplates options:(nullable NSDictionary<MGLTileSourceOption, id> *)options {
+ mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
+ auto source = std::make_unique<mbgl::style::VectorSource>(identifier.UTF8String, tileSet);
+ return self = [super initWithPendingSource:std::move(source)];
+}
+
+- (mbgl::style::VectorSource *)rawSource {
+ return (mbgl::style::VectorSource *)super.rawSource;
+}
+
+- (NSURL *)configurationURL {
+ auto url = self.rawSource->getURL();
+ return url ? [NSURL URLWithString:@(url->c_str())] : nil;
+}
+
+- (NSString *)attributionHTMLString {
+ auto attribution = self.rawSource->getAttribution();
+ return attribution ? @(attribution->c_str()) : nil;
+}
+
+- (NSArray<id <MGLFeature>> *)featuresInSourceLayersWithIdentifiers:(NSSet<NSString *> *)sourceLayerIdentifiers predicate:(nullable NSPredicate *)predicate {
+
+ mbgl::optional<std::vector<std::string>> optionalSourceLayerIDs;
+ if (sourceLayerIdentifiers) {
+ __block std::vector<std::string> layerIDs;
+ layerIDs.reserve(sourceLayerIdentifiers.count);
+ [sourceLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop) {
+ layerIDs.push_back(identifier.UTF8String);
+ }];
+ optionalSourceLayerIDs = layerIDs;
+ }
+
+ mbgl::optional<mbgl::style::Filter> optionalFilter;
+ if (predicate) {
+ optionalFilter = predicate.mgl_filter;
+ }
+
+ std::vector<mbgl::Feature> features;
+ if (self.mapView) {
+ features = self.mapView.renderer->querySourceFeatures(self.rawSource->getID(), { optionalSourceLayerIDs, optionalFilter });
+ }
+ return MGLFeaturesFromMBGLFeatures(features);
+}
+
+@end
+
+@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",
+];
+
++ (NSSet<NSString *> *)mapboxStreetsLanguages {
+ static dispatch_once_t onceToken;
+ static NSSet<NSString *> *mapboxStreetsLanguages;
+ dispatch_once(&onceToken, ^{
+ mapboxStreetsLanguages = [NSSet setWithArray:MGLMapboxStreetsLanguages];
+ });
+ return mapboxStreetsLanguages;
+}
+
++ (NSString *)preferredMapboxStreetsLanguage {
+ 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;
+ }
+ }
+ if ([mostSpecificLanguage isEqualToString:@"mul"]) {
+ return acceptsEnglish ? @"en" : nil;
+ }
+ return mostSpecificLanguage;
+}
+
+- (BOOL)isMapboxStreets {
+ NSURL *url = self.configurationURL;
+ if (![url.scheme isEqualToString:@"mapbox"]) {
+ return NO;
+ }
+ NSArray *identifiers = [url.host componentsSeparatedByString:@","];
+ return [identifiers containsObject:@"mapbox.mapbox-streets-v7"] || [identifiers containsObject:@"mapbox.mapbox-streets-v6"];
+}
+
+- (NSDictionary<NSString *, NSString *> *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage {
+ if (!self.mapboxStreets) {
+ return @{};
+ }
+
+ // 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 [MGLVectorTileSource mapboxStreetsLanguages]) {
+ NSString *key = [NSString stringWithFormat:@"name_%@", languageCode];
+ localizedKeysByKey[key] = localizedKey;
+ }
+ return localizedKeysByKey;
+}
+
+@end
diff --git a/platform/darwin/src/MGLVectorTileSource_Private.h b/platform/darwin/src/MGLVectorTileSource_Private.h
new file mode 100644
index 0000000000..8042e2cfee
--- /dev/null
+++ b/platform/darwin/src/MGLVectorTileSource_Private.h
@@ -0,0 +1,18 @@
+#import "MGLVectorTileSource.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MGLVectorTileSource (Private)
+
+@property (nonatomic, readonly, getter=isMapboxStreets) BOOL mapboxStreets;
+
++ (NSSet<NSString *> *)mapboxStreetsLanguages;
+
++ (nullable NSString *)preferredMapboxStreetsLanguage;
++ (nullable NSString *)preferredMapboxStreetsLanguageForPreferences:(NSArray<NSString *> *)preferencesArray;
+
+- (NSDictionary<NSString *, NSString *> *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/NSArray+MGLAdditions.mm b/platform/darwin/src/NSArray+MGLAdditions.mm
index 3cab7ff427..195e96b09d 100644
--- a/platform/darwin/src/NSArray+MGLAdditions.mm
+++ b/platform/darwin/src/NSArray+MGLAdditions.mm
@@ -1,7 +1,7 @@
#import "NSArray+MGLAdditions.h"
#import "NSDictionary+MGLAdditions.h"
-#import "NSExpression+MGLAdditions.mm"
+#import "NSExpression+MGLPrivateAdditions.h"
@implementation NSArray (MGLAdditions)
diff --git a/platform/darwin/src/NSBundle+MGLAdditions.h b/platform/darwin/src/NSBundle+MGLAdditions.h
index ad5e9d5369..86dc27f22c 100644
--- a/platform/darwin/src/NSBundle+MGLAdditions.h
+++ b/platform/darwin/src/NSBundle+MGLAdditions.h
@@ -34,7 +34,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (nullable NSString *)mgl_frameworkBundleIdentifier;
-+ (nullable NS_DICTIONARY_OF(NSString *, id) *)mgl_frameworkInfoDictionary;
++ (nullable NSDictionary<NSString *, id> *)mgl_frameworkInfoDictionary;
+ (nullable NSString *)mgl_applicationBundleIdentifier;
diff --git a/platform/darwin/src/NSBundle+MGLAdditions.m b/platform/darwin/src/NSBundle+MGLAdditions.m
index f55059324e..37f78963d3 100644
--- a/platform/darwin/src/NSBundle+MGLAdditions.m
+++ b/platform/darwin/src/NSBundle+MGLAdditions.m
@@ -26,7 +26,7 @@
return self.mgl_frameworkInfoDictionary[@"CFBundleIdentifier"];
}
-+ (nullable NS_DICTIONARY_OF(NSString *, id) *)mgl_frameworkInfoDictionary {
++ (nullable NSDictionary<NSString *, id> *)mgl_frameworkInfoDictionary {
NSBundle *bundle = self.mgl_frameworkBundle;
return bundle.infoDictionary;
}
diff --git a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
index ac2d598d05..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+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;
@@ -294,3 +75,76 @@
}
@end
+
+@implementation NSComparisonPredicate (MGLExpressionAdditions)
+
+- (id)mgl_jsonExpressionObject {
+ NSString *op;
+ switch (self.predicateOperatorType) {
+ case NSLessThanPredicateOperatorType:
+ op = @"<";
+ break;
+ case NSLessThanOrEqualToPredicateOperatorType:
+ op = @"<=";
+ break;
+ case NSGreaterThanPredicateOperatorType:
+ op = @">";
+ break;
+ case NSGreaterThanOrEqualToPredicateOperatorType:
+ op = @">=";
+ break;
+ case NSEqualToPredicateOperatorType:
+ op = @"==";
+ break;
+ 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 NSCustomSelectorPredicateOperatorType:
+ [NSException raise:NSInvalidArgumentException
+ format:@"NSPredicateOperatorType:%lu is not supported.", (unsigned long)self.predicateOperatorType];
+ }
+ if (op) {
+ return @[op, self.leftExpression.mgl_jsonExpressionObject, self.rightExpression.mgl_jsonExpressionObject];
+ }
+ return nil;
+}
+
+@end
diff --git a/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm b/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm
index 0039b5af82..5a98b763ea 100644
--- a/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm
+++ b/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm
@@ -1,7 +1,11 @@
#import "NSCompoundPredicate+MGLAdditions.h"
+#import "MGLStyleValue_Private.h"
+
#import "NSPredicate+MGLAdditions.h"
-#import "NSExpression+MGLAdditions.h"
+#import "NSExpression+MGLPrivateAdditions.h"
+
+#include <mbgl/style/conversion/property_value.hpp>
@implementation NSCompoundPredicate (MGLAdditions)
@@ -14,60 +18,32 @@
return filters;
}
-- (mbgl::style::Filter)mgl_filter
-{
+@end
+
+@implementation NSCompoundPredicate (MGLExpressionAdditions)
+
+- (id)mgl_jsonExpressionObject {
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;
+ return @[@"!", subpredicate.mgl_jsonExpressionObject];
}
+
case NSAndPredicateType: {
- mbgl::style::AllFilter filter;
- filter.filters = self.mgl_subfilters;
- return filter;
+ NSArray *subarrays = [self.subpredicates valueForKeyPath:@"mgl_jsonExpressionObject"];
+ return [@[@"all"] arrayByAddingObjectsFromArray:subarrays];
}
+
case NSOrPredicateType: {
- mbgl::style::AnyFilter filter;
- filter.filters = self.mgl_subfilters;
- return filter;
+ NSArray *subarrays = [self.subpredicates valueForKeyPath:@"mgl_jsonExpressionObject"];
+ return [@[@"any"] arrayByAddingObjectsFromArray:subarrays];
}
}
-
+
[NSException raise:@"Compound predicate type not handled"
format:@""];
- return {};
+ return nil;
}
@end
diff --git a/platform/darwin/src/NSDictionary+MGLAdditions.mm b/platform/darwin/src/NSDictionary+MGLAdditions.mm
index aad7fd8810..4bc7ddb3cf 100644
--- a/platform/darwin/src/NSDictionary+MGLAdditions.mm
+++ b/platform/darwin/src/NSDictionary+MGLAdditions.mm
@@ -1,6 +1,6 @@
#import "NSDictionary+MGLAdditions.h"
-#import "NSExpression+MGLAdditions.mm"
+#import "NSExpression+MGLPrivateAdditions.h"
#import "NSArray+MGLAdditions.h"
@implementation NSDictionary (MGLAdditions)
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.h b/platform/darwin/src/NSExpression+MGLAdditions.h
index 491ed5a536..cfdf27aade 100644
--- a/platform/darwin/src/NSExpression+MGLAdditions.h
+++ b/platform/darwin/src/NSExpression+MGLAdditions.h
@@ -1,17 +1,200 @@
#import <Foundation/Foundation.h>
+#if TARGET_OS_IPHONE
+ #import <UIKit/UIKit.h>
+#else
+ #import <Cocoa/Cocoa.h>
+#endif
-#include <mbgl/style/filter.hpp>
+#import "MGLTypes.h"
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)
-@property (nonatomic, readonly) mbgl::Value mgl_constantMBGLValue;
-@property (nonatomic, readonly) std::vector<mbgl::Value> mgl_aggregateMBGLValue;
-@property (nonatomic, readonly) mbgl::FeatureType mgl_featureType;
-@property (nonatomic, readonly) std::vector<mbgl::FeatureType> mgl_aggregateFeatureType;
-@property (nonatomic, readonly) mbgl::FeatureIdentifier mgl_featureIdentifier;
-@property (nonatomic, readonly) std::vector<mbgl::FeatureIdentifier> mgl_aggregateFeatureIdentifier;
+#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
+ “[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.
+
+ @param object A Foundation object deserialized from JSON data, for example
+ using `NSJSONSerialization`.
+ @return An initialized expression equivalent to `object`, suitable for use as
+ the value of a style layer attribute.
+ */
++ (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
+ “[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.
+
+ You can use `NSJSONSerialization` to serialize the Foundation object as data to
+ write to a file.
+ */
+@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
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm
index a7759cda9d..a42a2d276e 100644
--- a/platform/darwin/src/NSExpression+MGLAdditions.mm
+++ b/platform/darwin/src/NSExpression+MGLAdditions.mm
@@ -1,13 +1,249 @@
-#import "NSExpression+MGLAdditions.h"
+#import "NSExpression+MGLPrivateAdditions.h"
#import "MGLTypes.h"
#if TARGET_OS_IPHONE
#import "UIColor+MGLAdditions.h"
+ #define MGLEdgeInsets UIEdgeInsets
#else
#import "NSColor+MGLAdditions.h"
+ #define MGLEdgeInsets NSEdgeInsets
#endif
+#import "NSPredicate+MGLAdditions.h"
+#import "NSValue+MGLStyleAttributeAdditions.h"
+#import "MGLVectorTileSource_Private.h"
-@implementation NSExpression (MGLAdditions)
+#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 {
if ([self.constantValue isKindOfClass:[NSArray class]] || [self.constantValue isKindOfClass:[NSSet class]]) {
@@ -153,4 +389,1081 @@
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.
+ */
+NSArray<NSExpression *> *MGLCollectionByReplacingTokensWithKeyPaths(NSArray<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.
+ */
+NSDictionary<NSNumber *, NSExpression *> *MGLStopDictionaryByReplacingTokensWithKeyPaths(NSDictionary<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)
+
+- (NSNumber *)mgl_number {
+ return nil;
+}
+
+- (NSNumber *)mgl_numberWithFallbackValues:(id)fallbackValue, ... {
+ if (self.mgl_number) {
+ return self.mgl_number;
+ }
+
+ va_list fallbackValues;
+ va_start(fallbackValues, fallbackValue);
+ for (id value = fallbackValue; value; value = va_arg(fallbackValues, id)) {
+ if ([value mgl_number]) {
+ return [value mgl_number];
+ }
+ }
+
+ return nil;
+}
+
+@end
+
+@implementation NSNull (MGLExpressionAdditions)
+
+- (id)mgl_jsonExpressionObject {
+ return self;
+}
+
+@end
+
+@implementation NSString (MGLExpressionAdditions)
+
+- (id)mgl_jsonExpressionObject {
+ return self;
+}
+
+- (NSNumber *)mgl_number {
+ if (self.doubleValue || ![[NSDecimalNumber decimalNumberWithString:self] isEqual:[NSDecimalNumber notANumber]]) {
+ return @(self.doubleValue);
+ }
+
+ return nil;
+}
+
+@end
+
+@implementation NSNumber (MGLExpressionAdditions)
+
+- (id)mgl_interpolateWithCurveType:(NSString *)curveType
+ parameters:(NSArray *)parameters
+ stops:(NSDictionary<NSNumber *, id> *)stops {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Interpolation expressions lack underlying Objective-C implementations."];
+ return nil;
+}
+
+- (id)mgl_stepWithMinimum:(id)minimum stops:(NSDictionary<NSNumber *, id> *)stops {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Interpolation expressions lack underlying Objective-C implementations."];
+ return nil;
+}
+
+- (NSNumber *)mgl_number {
+ return self;
+}
+
+- (id)mgl_jsonExpressionObject {
+ if ([self isEqualToNumber:@(M_E)]) {
+ return @[@"e"];
+ } else if ([self isEqualToNumber:@(M_PI)]) {
+ return @[@"pi"];
+ }
+ return self;
+}
+
+@end
+
+@implementation MGLColor (MGLExpressionAdditions)
+
+- (id)mgl_jsonExpressionObject {
+ auto color = [self mgl_color];
+ if (color.a == 1) {
+ return @[@"rgb", @(color.r * 255), @(color.g * 255), @(color.b * 255)];
+ }
+ return @[@"rgba", @(color.r * 255), @(color.g * 255), @(color.b * 255), @(color.a)];
+}
+
+@end
+
+@implementation NSArray (MGLExpressionAdditions)
+
+- (id)mgl_jsonExpressionObject {
+ 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)
+
+- (id)mgl_jsonExpressionObject {
+ NSMutableDictionary *expressionObject = [NSMutableDictionary dictionaryWithCapacity:self.count];
+ [self enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
+ expressionObject[[key mgl_jsonExpressionObject]] = [obj mgl_jsonExpressionObject];
+ }];
+
+ return expressionObject;
+}
+
+- (id)mgl_has:(id)element {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Has expressions lack underlying Objective-C implementations."];
+ return nil;
+
+}
+
+@end
+
+@implementation NSExpression (MGLExpressionAdditions)
+
+- (NSExpression *)mgl_expressionWithContext:(NSDictionary<NSString *, NSExpression *> *)context {
+ [NSException raise:NSInternalInconsistencyException
+ format:@"Assignment expressions lack underlying Objective-C implementations."];
+ 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 {
+ return [NSExpression expressionForConditional:conditionPredicate trueExpression:trueExpression falseExpression: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 expressionWithMGLJSONObject:object];
+ [subexpressions addObject:expression];
+ }
+ return subexpressions;
+}
+
++ (instancetype)expressionWithMGLJSONObject:(id)object {
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ MGLFunctionNamesByExpressionOperator = @{
+ @"+": @"add:to:",
+ @"-": @"from:subtract:",
+ @"*": @"multiply:by:",
+ @"/": @"divide:by:",
+ @"%": @"modulus:by:",
+ @"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",
+ };
+ });
+
+ if (!object || object == [NSNull null]) {
+ return [NSExpression expressionForConstantValue:nil];
+ }
+
+ if ([object isKindOfClass:[NSString class]] ||
+ [object isKindOfClass:[NSNumber class]] ||
+ [object isKindOfClass:[NSValue class]] ||
+ [object isKindOfClass:[MGLColor class]]) {
+ return [NSExpression expressionForConstantValue:object];
+ }
+
+ 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 expressionWithMGLJSONObject:obj];
+ }];
+ return [NSExpression expressionForConstantValue:dictionary];
+ }
+
+ if ([object isKindOfClass:[NSArray class]]) {
+ NSArray *array = (NSArray *)object;
+ NSString *op = array.firstObject;
+
+ NSArray *argumentObjects = [array subarrayWithRange:NSMakeRange(1, array.count - 1)];
+
+ NSString *functionName = MGLFunctionNamesByExpressionOperator[op];
+ if (functionName) {
+ NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(argumentObjects);
+ if ([op isEqualToString:@"+"] && argumentObjects.count > 2) {
+ NSExpression *subexpression = [NSExpression expressionForAggregate:subexpressions];
+ return [NSExpression expressionForFunction:@"sum:"
+ arguments:@[subexpression]];
+ } else if ([op isEqualToString:@"^"] && [argumentObjects.firstObject isEqual:@[@"e"]]) {
+ functionName = @"exp:";
+ subexpressions = [subexpressions subarrayWithRange:NSMakeRange(1, subexpressions.count - 1)];
+ }
+
+ return [NSExpression expressionForFunction:functionName
+ arguments:subexpressions];
+ } else if ([op isEqualToString:@"literal"]) {
+ if ([argumentObjects.firstObject isKindOfClass:[NSArray class]]) {
+ return [NSExpression expressionForAggregate:MGLSubexpressionsWithJSONObjects(argumentObjects.firstObject)];
+ }
+ return [NSExpression expressionWithMGLJSONObject:argumentObjects.firstObject];
+ } else if ([op isEqualToString:@"to-boolean"]) {
+ NSExpression *operand = [NSExpression expressionWithMGLJSONObject:argumentObjects.firstObject];
+ return [NSExpression expressionForFunction:operand selectorName:@"boolValue" arguments:@[]];
+ } 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"] || [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 expressionWithMGLJSONObject:argumentObjects.lastObject];
+ if ([argumentObjects.firstObject isKindOfClass:[NSString class]]) {
+ return [NSExpression expressionWithFormat:@"%@.%K", operand, 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);
+ 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];
+ return [NSExpression expressionForFunction:@"min:" arguments:@[subexpression]];
+ } else if ([op isEqualToString:@"max"]) {
+ NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(argumentObjects);
+ NSExpression *subexpression = [NSExpression expressionForAggregate:subexpressions];
+ return [NSExpression expressionForFunction:@"max:" arguments:@[subexpression]];
+ } else if ([op isEqualToString:@"e"]) {
+ return [NSExpression expressionForConstantValue:@(M_E)];
+ } else if ([op isEqualToString:@"pi"]) {
+ return [NSExpression expressionForConstantValue:@(M_PI)];
+ } else if ([op isEqualToString:@"concat"]) {
+ NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(argumentObjects);
+ 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 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 expressionWithMGLJSONObject:curveParameters];
+ argumentObjects = [argumentObjects subarrayWithRange:NSMakeRange(1, argumentObjects.count - 1)];
+ 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 expressionWithMGLJSONObject:valueExpression];
+ }
+ NSExpression *stopExpression = [NSExpression expressionForConstantValue:stops];
+ return [NSExpression expressionForFunction:@"mgl_interpolate:withCurveType:parameters:stops:"
+ arguments:@[inputExpression, curveTypeExpression, curveParameterExpression, stopExpression]];
+ } else if ([op isEqualToString:@"step"]) {
+ NSExpression *inputExpression = [NSExpression expressionWithMGLJSONObject:argumentObjects[0]];
+ NSArray *stopExpressions = [argumentObjects subarrayWithRange:NSMakeRange(1, argumentObjects.count - 1)];
+ NSExpression *minimum;
+ if (stopExpressions.count % 2) {
+ minimum = [NSExpression expressionWithMGLJSONObject:stopExpressions.firstObject];
+ stopExpressions = [stopExpressions subarrayWithRange:NSMakeRange(1, stopExpressions.count - 1)];
+ }
+ NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:stopExpressions.count / 2];
+ NSEnumerator *stopEnumerator = stopExpressions.objectEnumerator;
+ while (NSNumber *key = stopEnumerator.nextObject) {
+ NSExpression *valueExpression = stopEnumerator.nextObject;
+ if (minimum) {
+ stops[key] = [NSExpression expressionWithMGLJSONObject:valueExpression];
+ } else {
+ minimum = [NSExpression expressionWithMGLJSONObject:valueExpression];
+ }
+ }
+ NSExpression *stopExpression = [NSExpression expressionForConstantValue:stops];
+ return [NSExpression expressionForFunction:@"mgl_step:from:stops:"
+ arguments:@[inputExpression, minimum, stopExpression]];
+ } else if ([op isEqualToString:@"zoom"]) {
+ return NSExpression.zoomLevelVariableExpression;
+ } else if ([op isEqualToString:@"heatmap-density"]) {
+ 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"]) {
+ 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]]];
+ }
+ }
+
+ 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 {
+ NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(array);
+ return [NSExpression expressionForFunction:@"MGL_FUNCTION" arguments:subexpressions];
+ }
+ }
+
+ [NSException raise:NSInvalidArgumentException
+ format:@"Unable to convert JSON object %@ to an NSExpression.", object];
+
+ return nil;
+}
+
+- (id)mgl_jsonExpressionObject {
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ MGLExpressionOperatorsByFunctionNames = @{
+ @"add:to:": @"+",
+ @"from:subtract:": @"-",
+ @"multiply:by:": @"*",
+ @"divide:by:": @"/",
+ @"modulus:by:": @"%",
+ @"sqrt:": @"sqrt",
+ @"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",
+ };
+ });
+
+ switch (self.expressionType) {
+ case NSVariableExpressionType: {
+ if ([self.variable isEqualToString:@"heatmapDensity"]) {
+ return @[@"heatmap-density"];
+ }
+ 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];
+ }
+
+ case NSConstantValueExpressionType: {
+ id constantValue = self.constantValue;
+ if (!constantValue || constantValue == [NSNull null]) {
+ return [NSNull null];
+ }
+ if ([constantValue isEqual:@(M_E)]) {
+ return @[@"e"];
+ }
+ if ([constantValue isEqual:@(M_PI)]) {
+ return @[@"pi"];
+ }
+ if ([constantValue isKindOfClass:[NSArray class]] ||
+ [constantValue isKindOfClass:[NSDictionary class]]) {
+ NSArray *collection = [constantValue mgl_jsonExpressionObject];
+ return @[@"literal", collection];
+ }
+ if ([constantValue isKindOfClass:[MGLColor class]]) {
+ auto color = [constantValue mgl_color];
+ if (color.a == 1) {
+ return @[@"rgb", @(color.r * 255), @(color.g * 255), @(color.b * 255)];
+ }
+ return @[@"rgba", @(color.r * 255), @(color.g * 255), @(color.b * 255), @(color.a)];
+ }
+ if ([constantValue isKindOfClass:[NSValue class]]) {
+ const auto boxedValue = (NSValue *)constantValue;
+ if (strcmp([boxedValue objCType], @encode(CGVector)) == 0) {
+ // offset [x, y]
+ std::array<float, 2> mglValue = boxedValue.mgl_offsetArrayValue;
+ return @[@"literal", @[@(mglValue[0]), @(mglValue[1])]];
+ }
+ if (strcmp([boxedValue objCType], @encode(MGLEdgeInsets)) == 0) {
+ // padding [x, y]
+ std::array<float, 4> mglValue = boxedValue.mgl_paddingArrayValue;
+ return @[@"literal", @[@(mglValue[0]), @(mglValue[1]), @(mglValue[2]), @(mglValue[3])]];
+ }
+ }
+ return self.constantValue;
+ }
+
+ case NSKeyPathExpressionType: {
+ NSArray *expressionObject;
+ for (NSString *pathComponent in self.keyPath.pathComponents.reverseObjectEnumerator) {
+ if (expressionObject) {
+ expressionObject = @[@"get", pathComponent, expressionObject];
+ } else {
+ expressionObject = @[@"get", pathComponent];
+ }
+ }
+ return expressionObject;
+ }
+
+ case NSFunctionExpressionType: {
+ NSString *function = self.function;
+ NSString *op = MGLExpressionOperatorsByFunctionNames[function];
+ if (op) {
+ NSArray *arguments = self.arguments.mgl_jsonExpressionObject;
+ return [@[op] arrayByAddingObjectsFromArray:arguments];
+ } 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];
+ NSExpression *count = [NSExpression expressionForFunction:@"count:" arguments:self.arguments];
+ return [NSExpression expressionForFunction:@"divide:by:" arguments:@[sum, count]].mgl_jsonExpressionObject;
+ } else if ([function isEqualToString:@"sum:"]) {
+ NSArray *arguments = [self.arguments.firstObject.collection valueForKeyPath:@"mgl_jsonExpressionObject"];
+ return [@[@"+"] arrayByAddingObjectsFromArray:arguments];
+ } else if ([function isEqualToString:@"count:"]) {
+ NSArray *arguments = self.arguments.firstObject.mgl_jsonExpressionObject;
+ return @[@"length", arguments];
+ } else if ([function isEqualToString:@"min:"]) {
+ NSArray *arguments = [self.arguments.firstObject.collection valueForKeyPath:@"mgl_jsonExpressionObject"];
+ return [@[@"min"] arrayByAddingObjectsFromArray:arguments];
+ } else if ([function isEqualToString:@"max:"]) {
+ NSArray *arguments = [self.arguments.firstObject.collection valueForKeyPath:@"mgl_jsonExpressionObject"];
+ 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:@"trunc:"]) {
+ return [NSExpression expressionWithFormat:@"%@ - modulus:by:(%@, 1)",
+ 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_number"] ||
+ [function isEqualToString:@"mgl_numberWithFallbackValues:"] ||
+ [function isEqualToString:@"decimalValue"] ||
+ [function isEqualToString:@"floatValue"] ||
+ [function isEqualToString:@"doubleValue"]) {
+ NSArray *arguments = self.arguments.mgl_jsonExpressionObject;
+ return [@[@"to-number", self.operand.mgl_jsonExpressionObject] arrayByAddingObjectsFromArray:arguments];
+ } else if ([function isEqualToString:@"stringValue"]) {
+ return @[@"to-string", self.operand.mgl_jsonExpressionObject];
+ } else if ([function isEqualToString:@"noindex:"]) {
+ return self.arguments.firstObject.mgl_jsonExpressionObject;
+ } 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]]) {
+ context = [context constantValue];
+ }
+ NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"let", nil];
+ [context enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, NSExpression * _Nonnull obj, BOOL * _Nonnull stop) {
+ [expressionObject addObject:key];
+ [expressionObject addObject:obj.mgl_jsonExpressionObject];
+ }];
+ [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:"] ||
+ [function isEqualToString:@"random"] ||
+ [function isEqualToString:@"randomn:"] ||
+ [function isEqualToString:@"now"] ||
+ [function isEqualToString:@"bitwiseAnd:with:"] ||
+ [function isEqualToString:@"bitwiseOr:with:"] ||
+ [function isEqualToString:@"bitwiseXor:with:"] ||
+ [function isEqualToString:@"leftshift:by:"] ||
+ [function isEqualToString:@"rightshift:by:"] ||
+ [function isEqualToString:@"onesComplement:"] ||
+ [function isEqualToString:@"distanceToLocation:fromLocation:"]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Expression function %@ not yet implemented.", function];
+ return nil;
+ } else {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Unrecognized expression function %@.", function];
+ return nil;
+ }
+ }
+
+ case NSConditionalExpressionType: {
+ 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;
+ falseArguments = [falseArguments subarrayWithRange:NSMakeRange(1, falseArguments.count - 1)];
+ [arguments addObjectsFromArray:falseArguments];
+ } else {
+ [arguments addObject:self.falseExpression.mgl_jsonExpressionObject];
+ }
+
+ [arguments insertObject:@"case" atIndex:0];
+ return arguments;
+ }
+
+ case NSAggregateExpressionType: {
+ NSArray *collection = [self.collection valueForKeyPath:@"mgl_jsonExpressionObject"];
+ return @[@"literal", collection];
+ }
+
+ case NSEvaluatedObjectExpressionType:
+ case NSUnionSetExpressionType:
+ case NSIntersectSetExpressionType:
+ case NSMinusSetExpressionType:
+ case NSSubqueryExpressionType:
+ case NSAnyKeyExpressionType:
+ case NSBlockExpressionType:
+ [NSException raise:NSInvalidArgumentException
+ format:@"Expression type %lu not yet implemented.", self.expressionType];
+ }
+
+ // NSKeyPathSpecifierExpression
+ if (self.expressionType == 10) {
+ return self.description;
+ }
+ // An assignment expression type is present in the BNF grammar, but the
+ // corresponding NSExpressionType value and property getters are missing.
+ if (self.expressionType == 12) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Assignment expressions not yet implemented."];
+ }
+
+ 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.
+ */
+NSArray<NSExpression *> *MGLLocalizedCollection(NSArray<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.
+ */
+NSDictionary<NSNumber *, NSExpression *> *MGLLocalizedStopDictionary(NSDictionary<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: {
+ 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
new file mode 100644
index 0000000000..a1948f9e45
--- /dev/null
+++ b/platform/darwin/src/NSExpression+MGLPrivateAdditions.h
@@ -0,0 +1,89 @@
+#import <Foundation/Foundation.h>
+#if TARGET_OS_IPHONE
+ #import <UIKit/UIKit.h>
+#else
+ #import <Cocoa/Cocoa.h>
+#endif
+
+#import "NSExpression+MGLAdditions.h"
+
+#include <mbgl/style/filter.hpp>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface NSObject (MGLExpressionAdditions)
+
+- (NSNumber *)mgl_number;
+- (NSNumber *)mgl_numberWithFallbackValues:(id)fallbackValue, ... NS_REQUIRES_NIL_TERMINATION;
+
+@end
+
+@interface NSExpression (MGLPrivateAdditions)
+
+@property (nonatomic, readonly) mbgl::Value mgl_constantMBGLValue;
+@property (nonatomic, readonly) std::vector<mbgl::Value> mgl_aggregateMBGLValue;
+@property (nonatomic, readonly) mbgl::FeatureType mgl_featureType;
+@property (nonatomic, readonly) std::vector<mbgl::FeatureType> mgl_aggregateFeatureType;
+@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)
+
+@property (nonatomic, readonly) id mgl_jsonExpressionObject;
+
+@end
+
+@interface NSString (MGLExpressionAdditions)
+
+@property (nonatomic, readonly) id mgl_jsonExpressionObject;
+
+@end
+
+@interface NSNumber (MGLExpressionAdditions)
+
+- (id)mgl_interpolateWithCurveType:(NSString *)curveType parameters:(NSArray *)parameters stops:(NSDictionary<NSNumber *, id> *)stops;
+- (id)mgl_stepWithMinimum:(id)minimum stops:(NSDictionary<NSNumber *, id> *)stops;
+
+@property (nonatomic, readonly) id mgl_jsonExpressionObject;
+
+@end
+
+@interface NSArray (MGLExpressionAdditions)
+
+@property (nonatomic, readonly) id mgl_jsonExpressionObject;
+
+@end
+
+@interface NSDictionary (MGLExpressionAdditions)
+
+@property (nonatomic, readonly) id mgl_jsonExpressionObject;
+
+- (id)mgl_has:(id)element;
+
+@end
+
+@interface MGLColor (MGLExpressionAdditions)
+
+@property (nonatomic, readonly) id mgl_jsonExpressionObject;
+
+@end
+
+@interface NSExpression (MGLExpressionAdditions)
+
+- (NSExpression *)mgl_expressionWithContext:(NSDictionary<NSString *, NSExpression *> *)context;
+
+
+- (id)mgl_has:(id)element;
+
+@end
+
+extern NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects);
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/NSPredicate+MGLAdditions.h b/platform/darwin/src/NSPredicate+MGLAdditions.h
index fd774dd58b..a73b1a61ba 100644
--- a/platform/darwin/src/NSPredicate+MGLAdditions.h
+++ b/platform/darwin/src/NSPredicate+MGLAdditions.h
@@ -1,7 +1,6 @@
#import <Foundation/Foundation.h>
-#import "NSExpression+MGLAdditions.h"
-#include <mbgl/style/filter.hpp>
+#import "NSExpression+MGLPrivateAdditions.h"
@interface NSPredicate (MGLAdditions)
@@ -11,3 +10,14 @@
@end
+@interface NSPredicate (MGLExpressionAdditions)
+
++ (instancetype)mgl_predicateWithJSONObject:(id)object;
+
+@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 e0511d8740..bbd324bb63 100644
--- a/platform/darwin/src/NSPredicate+MGLAdditions.mm
+++ b/platform/darwin/src/NSPredicate+MGLAdditions.mm
@@ -1,6 +1,9 @@
#import "NSPredicate+MGLAdditions.h"
#import "MGLValueEvaluator.h"
+#import "MGLStyleValue_Private.h"
+
+#include <mbgl/style/conversion/filter.hpp>
class FilterEvaluator {
public:
@@ -194,37 +197,198 @@ public:
NSPredicate *operator()(mbgl::style::NotHasIdentifierFilter filter) {
return [NSPredicate predicateWithFormat:@"%K == nil", @"$id"];
}
+
+ NSPredicate *operator()(mbgl::style::ExpressionFilter filter) {
+ id jsonObject = MGLJSONObjectFromMBGLExpression(*filter.expression);
+ return [NSPredicate mgl_predicateWithJSONObject:jsonObject];
+ }
};
@implementation NSPredicate (MGLAdditions)
- (mbgl::style::Filter)mgl_filter
{
- if ([self isEqual:[NSPredicate predicateWithValue:YES]])
- {
- return mbgl::style::AllFilter();
+ 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:@"Invalid filter value: %@", @(valueError.message.c_str())];
+ return {};
}
+ mbgl::style::Filter filter = std::move(*value);
+
+ return filter;
+}
+
++ (instancetype)mgl_predicateWithFilter:(mbgl::style::Filter)filter
+{
+ FilterEvaluator evaluator;
+ return mbgl::style::Filter::visit(filter, evaluator);
+}
- if ([self isEqual:[NSPredicate predicateWithValue:NO]])
- {
- return mbgl::style::AnyFilter();
+@end
+
+@implementation NSPredicate (MGLExpressionAdditions)
+
+NSArray *MGLSubpredicatesWithJSONObjects(NSArray *objects) {
+ NSMutableArray *subpredicates = [NSMutableArray arrayWithCapacity:objects.count];
+ for (id object in objects) {
+ NSPredicate *predicate = [NSPredicate mgl_predicateWithJSONObject:object];
+ [subpredicates addObject:predicate];
}
+ return subpredicates;
+}
- if ([self.predicateFormat hasPrefix:@"BLOCKPREDICATE("])
- {
++ (instancetype)mgl_predicateWithJSONObject:(id)object {
+ if ([object isEqual:@YES]) {
+ return [NSPredicate predicateWithValue:YES];
+ }
+ if ([object isEqual:@NO]) {
+ return [NSPredicate predicateWithValue:NO];
+ }
+
+ NSAssert([object isKindOfClass:[NSArray class]], @"Condition for case expression should be an expression.");
+ NSArray *objects = (NSArray *)object;
+ NSString *op = objects.firstObject;
+
+ if ([op isEqualToString:@"=="]) {
+ NSArray *subexpressions = MGLSubexpressionsWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
+ return [NSPredicate predicateWithFormat:@"%@ == %@" argumentArray:subexpressions];
+ }
+ if ([op isEqualToString:@"!="]) {
+ NSArray *subexpressions = MGLSubexpressionsWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
+ return [NSPredicate predicateWithFormat:@"%@ != %@" argumentArray:subexpressions];
+ }
+ if ([op isEqualToString:@"<"]) {
+ NSArray *subexpressions = MGLSubexpressionsWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
+ return [NSPredicate predicateWithFormat:@"%@ < %@" argumentArray:subexpressions];
+ }
+ if ([op isEqualToString:@"<="]) {
+ NSArray *subexpressions = MGLSubexpressionsWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
+ return [NSPredicate predicateWithFormat:@"%@ <= %@" argumentArray:subexpressions];
+ }
+ if ([op isEqualToString:@">"]) {
+ NSArray *subexpressions = MGLSubexpressionsWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
+ return [NSPredicate predicateWithFormat:@"%@ > %@" argumentArray:subexpressions];
+ }
+ if ([op isEqualToString:@">="]) {
+ NSArray *subexpressions = MGLSubexpressionsWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
+ return [NSPredicate predicateWithFormat:@"%@ >= %@" argumentArray:subexpressions];
+ }
+ if ([op isEqualToString:@"!"]) {
+ NSArray *subpredicates = MGLSubpredicatesWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
+ if (subpredicates.count > 1) {
+ NSCompoundPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:subpredicates];
+ return [NSCompoundPredicate notPredicateWithSubpredicate:predicate];
+ }
+ if (subpredicates.count) {
+ return [NSCompoundPredicate notPredicateWithSubpredicate:subpredicates.firstObject];
+ }
+ return [NSPredicate predicateWithValue:YES];
+ }
+ if ([op isEqualToString:@"all"]) {
+ 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"]) {
+ NSArray *subpredicates = MGLSubpredicatesWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
+ return [NSCompoundPredicate orPredicateWithSubpredicates:subpredicates];
+ }
+
+ NSExpression *expression = [NSExpression expressionWithMGLJSONObject:object];
+ return [NSComparisonPredicate predicateWithLeftExpression:expression
+ rightExpression:[NSExpression expressionForConstantValue:@YES]
+ modifier:NSDirectPredicateModifier
+ type:NSEqualToPredicateOperatorType
+ options:0];
+
+}
+
+- (id)mgl_jsonExpressionObject {
+ if ([self isEqual:[NSPredicate predicateWithValue:YES]]) {
+ return @YES;
+ }
+ if ([self isEqual:[NSPredicate predicateWithValue:NO]]) {
+ return @NO;
+ }
+
+ if ([self.predicateFormat hasPrefix:@"BLOCKPREDICATE("]) {
[NSException raise:NSInvalidArgumentException
format:@"Block-based predicates are not supported."];
}
-
+
[NSException raise:NSInvalidArgumentException
format:@"Unrecognized predicate type."];
- return {};
+ return nil;
}
-+ (instancetype)mgl_predicateWithFilter:(mbgl::style::Filter)filter
-{
- FilterEvaluator evaluator;
- return mbgl::style::Filter::visit(filter, evaluator);
+- (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.h b/platform/darwin/src/NSString+MGLAdditions.h
index d82ecaa671..4888c7a00f 100644
--- a/platform/darwin/src/NSString+MGLAdditions.h
+++ b/platform/darwin/src/NSString+MGLAdditions.h
@@ -20,6 +20,17 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (NSString *)mgl_titleCasedStringWithLocale:(NSLocale *)locale;
+/**
+ Returns a transliterated representation of the receiver using the specified
+ script. If transliteration fails, the receiver will be returned.
+
+ Only supports scripts for languages used by Mapbox Streets.
+
+ @param script The four-letter code representing the name of the script, as
+ specified by ISO 15924.
+ */
+- (NSString *)mgl_stringByTransliteratingIntoScript:(NSString *)script;
+
@end
@interface NSAttributedString (MGLAdditions)
diff --git a/platform/darwin/src/NSString+MGLAdditions.m b/platform/darwin/src/NSString+MGLAdditions.m
index cde4bddcc3..d645490eb3 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,14 +17,9 @@
- (NSString *)mgl_titleCasedStringWithLocale:(NSLocale *)locale {
NSMutableString *string = self.mutableCopy;
NSOrthography *orthography;
-#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunguarded-availability-new"
- if ([NSOrthography respondsToSelector:@selector(defaultOrthographyForLanguage:)]) {
+ if (@available(iOS 11.0, macOS 10.13.0, *)) {
orthography = [NSOrthography defaultOrthographyForLanguage:locale.localeIdentifier];
}
-#pragma clang diagnostic pop
-#endif
[string enumerateLinguisticTagsInRange:string.mgl_wholeRange scheme:NSLinguisticTagSchemeLexicalClass options:0 orthography:orthography usingBlock:^(NSString * _Nonnull tag, NSRange tokenRange, NSRange sentenceRange, BOOL * _Nonnull stop) {
NSString *word = [string substringWithRange:tokenRange];
if (word.length > 3
@@ -41,6 +40,21 @@
return string;
}
+- (NSString *)mgl_stringByTransliteratingIntoScript:(NSString *)script {
+ NSMutableString *string = self.mutableCopy;
+ NSStringTransform transform;
+ if ([script isEqualToString:@"Latn"]) {
+ transform = NSStringTransformToLatin;
+ } else if ([script isEqualToString:@"Hans"]) {
+ // No transform available.
+ } else if ([script isEqualToString:@"Cyrl"]) {
+ transform = @"Any-Latin; Latin-Cyrillic";
+ } else if ([script isEqualToString:@"Arab"]) {
+ transform = @"Any-Latin; Latin-Arabic";
+ }
+ return transform ? [string stringByApplyingTransform:transform reverse:NO] : string;
+}
+
@end
@implementation NSAttributedString (MGLAdditions)
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)];
}
diff --git a/platform/darwin/src/headless_backend_cgl.cpp b/platform/darwin/src/headless_backend_cgl.cpp
index 3b0c3aaf35..46a5beb870 100644
--- a/platform/darwin/src/headless_backend_cgl.cpp
+++ b/platform/darwin/src/headless_backend_cgl.cpp
@@ -1,5 +1,5 @@
#include <mbgl/gl/headless_backend.hpp>
-#include <mbgl/gl/headless_display.hpp>
+#include <mbgl/util/logging.hpp>
#include <OpenGL/OpenGL.h>
#include <CoreFoundation/CoreFoundation.h>
@@ -9,14 +9,96 @@
namespace mbgl {
-struct CGLImpl : public HeadlessBackend::Impl {
- CGLImpl(CGLContextObj glContext_) : glContext(glContext_) {
+// This class provides a singleton that contains information about the pixel format used for
+// instantiating new headless rendering contexts.
+class CGLDisplayConfig {
+private:
+ // Key for singleton construction.
+ struct Key { explicit Key() = default; };
+
+public:
+ CGLDisplayConfig(Key) {
+ // TODO: test if OpenGL 4.1 with GL_ARB_ES2_compatibility is supported
+ // If it is, use kCGLOGLPVersion_3_2_Core and enable that extension.
+ CGLPixelFormatAttribute attributes[] = {
+ kCGLPFAOpenGLProfile, static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_Legacy),
+ // Not adding kCGLPFAAccelerated, as this will make headless rendering impossible when running in VMs.
+ kCGLPFAClosestPolicy,
+ kCGLPFAAccumSize, static_cast<CGLPixelFormatAttribute>(32),
+ kCGLPFAColorSize, static_cast<CGLPixelFormatAttribute>(24),
+ kCGLPFAAlphaSize, static_cast<CGLPixelFormatAttribute>(8),
+ kCGLPFADepthSize, static_cast<CGLPixelFormatAttribute>(16),
+ kCGLPFAStencilSize, static_cast<CGLPixelFormatAttribute>(8),
+ kCGLPFASupportsAutomaticGraphicsSwitching,
+ kCGLPFAAllowOfflineRenderers, // Allows using the integrated GPU
+ static_cast<CGLPixelFormatAttribute>(0)
+ };
+
+ GLint num;
+ // TODO: obtain all configurations and choose the best one.
+ const CGLError error = CGLChoosePixelFormat(attributes, &pixelFormat, &num);
+ if (error != kCGLNoError) {
+ throw std::runtime_error(std::string("Error choosing pixel format:") + CGLErrorString(error) + "\n");
+ }
+ if (num <= 0) {
+ throw std::runtime_error("No pixel formats found.");
+ }
+ }
+
+ ~CGLDisplayConfig() {
+ const CGLError error = CGLDestroyPixelFormat(pixelFormat);
+ if (error != kCGLNoError) {
+ Log::Error(Event::OpenGL, std::string("Error destroying pixel format:") + CGLErrorString(error));
+ }
+ }
+
+ static std::shared_ptr<const CGLDisplayConfig> create() {
+ static std::weak_ptr<const CGLDisplayConfig> instance;
+ auto shared = instance.lock();
+ if (!shared) {
+ instance = shared = std::make_shared<CGLDisplayConfig>(Key{});
+ }
+ return shared;
+ }
+
+public:
+ CGLPixelFormatObj pixelFormat = nullptr;
+};
+
+class CGLBackendImpl : public HeadlessBackend::Impl {
+public:
+ CGLBackendImpl() {
+ CGLError error = CGLCreateContext(cglDisplay->pixelFormat, nullptr, &glContext);
+ if (error != kCGLNoError) {
+ throw std::runtime_error(std::string("Error creating GL context object:") +
+ CGLErrorString(error) + "\n");
+ }
+
+ error = CGLEnable(glContext, kCGLCEMPEngine);
+ if (error != kCGLNoError) {
+ throw std::runtime_error(std::string("Error enabling OpenGL multithreading:") +
+ CGLErrorString(error) + "\n");
+ }
}
- ~CGLImpl() {
+ ~CGLBackendImpl() final {
CGLDestroyContext(glContext);
}
+ gl::ProcAddress getExtensionFunctionPointer(const char* name) final {
+ static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
+ if (!framework) {
+ throw std::runtime_error("Failed to load OpenGL framework.");
+ }
+
+ CFStringRef str =
+ CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
+ void* symbol = CFBundleGetFunctionPointerForName(framework, str);
+ CFRelease(str);
+
+ return reinterpret_cast<gl::ProcAddress>(symbol);
+ }
+
void activateContext() final {
CGLError error = CGLSetCurrentContext(glContext);
if (error != kCGLNoError) {
@@ -33,46 +115,14 @@ struct CGLImpl : public HeadlessBackend::Impl {
}
}
+private:
+ const std::shared_ptr<const CGLDisplayConfig> cglDisplay = CGLDisplayConfig::create();
CGLContextObj glContext = nullptr;
};
-gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) {
- static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
- if (!framework) {
- throw std::runtime_error("Failed to load OpenGL framework.");
- }
-
- CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
- void* symbol = CFBundleGetFunctionPointerForName(framework, str);
- CFRelease(str);
-
- return reinterpret_cast<gl::ProcAddress>(symbol);
-}
-
-bool HeadlessBackend::hasDisplay() {
- if (!display) {
- display = HeadlessDisplay::create();
- }
- return bool(display);
-}
-
-void HeadlessBackend::createContext() {
- assert(!hasContext());
-
- CGLContextObj glContext = nullptr;
- CGLError error = CGLCreateContext(display->attribute<CGLPixelFormatObj>(), nullptr, &glContext);
- if (error != kCGLNoError) {
- throw std::runtime_error(std::string("Error creating GL context object:") +
- CGLErrorString(error) + "\n");
- }
-
- error = CGLEnable(glContext, kCGLCEMPEngine);
- if (error != kCGLNoError) {
- throw std::runtime_error(std::string("Error enabling OpenGL multithreading:") +
- CGLErrorString(error) + "\n");
- }
-
- impl.reset(new CGLImpl(glContext));
+void HeadlessBackend::createImpl() {
+ assert(!impl);
+ impl = std::make_unique<CGLBackendImpl>();
}
} // namespace mbgl
diff --git a/platform/darwin/src/headless_backend_eagl.mm b/platform/darwin/src/headless_backend_eagl.mm
index f291c0805a..050fa62c78 100644
--- a/platform/darwin/src/headless_backend_eagl.mm
+++ b/platform/darwin/src/headless_backend_eagl.mm
@@ -6,52 +6,48 @@
namespace mbgl {
-struct EAGLImpl : public HeadlessBackend::Impl {
- EAGLImpl() {
+class EAGLBackendImpl : public HeadlessBackend::Impl {
+public:
+ EAGLBackendImpl() {
glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
-
if (glContext == nil) {
throw std::runtime_error("Error creating GL context object");
}
glContext.multiThreaded = YES;
}
- ~EAGLImpl() {
- [glContext release];
+ // Required for ARC to deallocate correctly.
+ ~EAGLBackendImpl() final = default;
+
+ gl::ProcAddress getExtensionFunctionPointer(const char* name) final {
+ static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles"));
+ if (!framework) {
+ throw std::runtime_error("Failed to load OpenGL framework.");
+ }
+
+ CFStringRef str =
+ CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
+ void* symbol = CFBundleGetFunctionPointerForName(framework, str);
+ CFRelease(str);
+
+ return reinterpret_cast<gl::ProcAddress>(symbol);
}
- void activateContext() {
+ void activateContext() final {
[EAGLContext setCurrentContext:glContext];
}
- void deactivateContext() {
+ void deactivateContext() final {
[EAGLContext setCurrentContext:nil];
}
+private:
EAGLContext* glContext = nullptr;
};
-gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) {
- static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles"));
- if (!framework) {
- throw std::runtime_error("Failed to load OpenGL framework.");
- }
-
- CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
- void* symbol = CFBundleGetFunctionPointerForName(framework, str);
- CFRelease(str);
-
- return reinterpret_cast<gl::ProcAddress>(symbol);
-}
-
-bool HeadlessBackend::hasDisplay() {
- return true;
-}
-
-void HeadlessBackend::createContext() {
- impl.reset();
- impl = std::make_unique<EAGLImpl>();
-
+void HeadlessBackend::createImpl() {
+ assert(!impl);
+ impl = std::make_unique<EAGLBackendImpl>();
}
} // namespace mbgl
diff --git a/platform/darwin/src/headless_display_cgl.cpp b/platform/darwin/src/headless_display_cgl.cpp
deleted file mode 100644
index 5b7a1f2bac..0000000000
--- a/platform/darwin/src/headless_display_cgl.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-#include <mbgl/gl/headless_display.hpp>
-
-#include <OpenGL/OpenGL.h>
-
-#include <stdexcept>
-#include <string>
-
-namespace mbgl {
-
-class HeadlessDisplay::Impl {
-public:
- Impl();
- ~Impl();
- CGLPixelFormatObj pixelFormat = nullptr;
-};
-
-HeadlessDisplay::Impl::Impl() {
- // TODO: test if OpenGL 4.1 with GL_ARB_ES2_compatibility is supported
- // If it is, use kCGLOGLPVersion_3_2_Core and enable that extension.
- CGLPixelFormatAttribute attributes[] = {
- kCGLPFAOpenGLProfile, static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_Legacy),
- // Not adding kCGLPFAAccelerated, as this will make headless rendering impossible when running in VMs.
- kCGLPFAClosestPolicy,
- kCGLPFAAccumSize, static_cast<CGLPixelFormatAttribute>(32),
- kCGLPFAColorSize, static_cast<CGLPixelFormatAttribute>(24),
- kCGLPFAAlphaSize, static_cast<CGLPixelFormatAttribute>(8),
- kCGLPFADepthSize, static_cast<CGLPixelFormatAttribute>(16),
- kCGLPFAStencilSize, static_cast<CGLPixelFormatAttribute>(8),
- kCGLPFASupportsAutomaticGraphicsSwitching,
- kCGLPFAAllowOfflineRenderers, // Allows using the integrated GPU
- static_cast<CGLPixelFormatAttribute>(0)
- };
-
- GLint num;
- CGLError error = CGLChoosePixelFormat(attributes, &pixelFormat, &num);
- if (error != kCGLNoError) {
- throw std::runtime_error(std::string("Error choosing pixel format:") + CGLErrorString(error) + "\n");
- }
- if (num <= 0) {
- throw std::runtime_error("No pixel formats found.");
- }
-}
-
-HeadlessDisplay::Impl::~Impl() {
- CGLDestroyPixelFormat(pixelFormat);
-}
-
-template <>
-CGLPixelFormatObj HeadlessDisplay::attribute() const {
- return impl->pixelFormat;
-}
-
-HeadlessDisplay::HeadlessDisplay()
- : impl(std::make_unique<Impl>()) {
-}
-
-HeadlessDisplay::~HeadlessDisplay() {
-}
-
-} // namespace mbgl
diff --git a/platform/darwin/src/image.mm b/platform/darwin/src/image.mm
index 8c0d5fa484..3a5adcca0a 100644
--- a/platform/darwin/src/image.mm
+++ b/platform/darwin/src/image.mm
@@ -11,7 +11,7 @@ using CGDataProviderHandle = CFHandle<CGDataProviderRef, CGDataProviderRef, CGDa
using CGColorSpaceHandle = CFHandle<CGColorSpaceRef, CGColorSpaceRef, CGColorSpaceRelease>;
using CGContextHandle = CFHandle<CGContextRef, CGContextRef, CGContextRelease>;
-CGImageRef CGImageFromMGLPremultipliedImage(mbgl::PremultipliedImage&& src) {
+CGImageRef CGImageCreateWithMGLPremultipliedImage(mbgl::PremultipliedImage&& src) {
// We're converting the PremultipliedImage's backing store to a CGDataProvider, and are taking
// over ownership of the memory.
CGDataProviderHandle provider(CGDataProviderCreateWithData(
diff --git a/platform/darwin/src/run_loop.cpp b/platform/darwin/src/run_loop.cpp
index d60a88cf52..0778b004e5 100644
--- a/platform/darwin/src/run_loop.cpp
+++ b/platform/darwin/src/run_loop.cpp
@@ -29,11 +29,8 @@ RunLoop::~RunLoop() {
Scheduler::SetCurrent(nullptr);
}
-void RunLoop::push(std::shared_ptr<WorkTask> task) {
- withMutex([&] {
- queue.push(std::move(task));
- impl->async->send();
- });
+void RunLoop::wake() {
+ impl->async->send();
}
void RunLoop::run() {
diff --git a/platform/darwin/test/MGLAttributionInfoTests.m b/platform/darwin/test/MGLAttributionInfoTests.m
index ed4927d44b..5961b61133 100644
--- a/platform/darwin/test/MGLAttributionInfoTests.m
+++ b/platform/darwin/test/MGLAttributionInfoTests.m
@@ -17,7 +17,7 @@
@"<a class=\"mapbox-improve-map\" href=\"https://www.mapbox.com/map-feedback/\" target=\"_blank\">Improve this map</a>",
};
- NS_MUTABLE_ARRAY_OF(MGLAttributionInfo *) *infos = [NSMutableArray array];
+ NSMutableArray<MGLAttributionInfo *> *infos = [NSMutableArray array];
for (NSUInteger i = 0; i < sizeof(htmlStrings) / sizeof(htmlStrings[0]); i++) {
NSArray *subinfos = [MGLAttributionInfo attributionInfosFromHTMLString:htmlStrings[i]
fontSize:0
@@ -51,12 +51,12 @@
XCTAssertEqualObjects([infos[3] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14],
[NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.sdk.ios#/77.63680/12.98108/14.00/0.0/0"]);
XCTAssertEqualObjects([infos[3] feedbackURLForStyleURL:styleURL atCenterCoordinate:mapbox zoomLevel:3.14159 direction:90.9 pitch:12.5],
- [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.sdk.ios&owner=mapbox&id=satellite-streets-v99&access_token#/77.63680/12.98108/3.14/90.9/13"]);
+ [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.sdk.ios&owner=mapbox&id=satellite-streets-v99&access_token&map_sdk_version=1.0.0#/77.63680/12.98108/3.14/90.9/13"]);
#else
XCTAssertEqualObjects([infos[3] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14],
[NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.MapboxGL#/77.63680/12.98108/14.00/0.0/0"]);
XCTAssertEqualObjects([infos[3] feedbackURLForStyleURL:styleURL atCenterCoordinate:mapbox zoomLevel:3.14159 direction:90.9 pitch:12.5],
- [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.MapboxGL&owner=mapbox&id=satellite-streets-v99&access_token#/77.63680/12.98108/3.14/90.9/13"]);
+ [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.MapboxGL&owner=mapbox&id=satellite-streets-v99&access_token&map_sdk_version=1.0.0#/77.63680/12.98108/3.14/90.9/13"]);
#endif
}
@@ -67,7 +67,7 @@
CGFloat fontSize = 72;
MGLColor *color = [MGLColor redColor];
- NS_MUTABLE_ARRAY_OF(MGLAttributionInfo *) *infos = [NSMutableArray array];
+ NSMutableArray<MGLAttributionInfo *> *infos = [NSMutableArray array];
for (NSUInteger i = 0; i < sizeof(htmlStrings) / sizeof(htmlStrings[0]); i++) {
NSArray *subinfos = [MGLAttributionInfo attributionInfosFromHTMLString:htmlStrings[i]
fontSize:72
@@ -109,7 +109,7 @@
@"Hello World",
};
- NS_MUTABLE_ARRAY_OF(MGLAttributionInfo *) *infos = [NSMutableArray array];
+ NSMutableArray<MGLAttributionInfo *> *infos = [NSMutableArray array];
for (NSUInteger i = 0; i < sizeof(htmlStrings) / sizeof(htmlStrings[0]); i++) {
NSArray *subinfos = [MGLAttributionInfo attributionInfosFromHTMLString:htmlStrings[i]
fontSize:0
diff --git a/platform/darwin/test/MGLBackgroundStyleLayerTests.mm b/platform/darwin/test/MGLBackgroundStyleLayerTests.mm
index c96a4fe7fa..de8080f425 100644
--- a/platform/darwin/test/MGLBackgroundStyleLayerTests.mm
+++ b/platform/darwin/test/MGLBackgroundStyleLayerTests.mm
@@ -31,39 +31,44 @@
{
XCTAssertTrue(rawLayer->getBackgroundColor().isUndefined(),
@"background-color should be unset initially.");
- MGLStyleValue<MGLColor *> *defaultStyleValue = layer.backgroundColor;
+ NSExpression *defaultExpression = layer.backgroundColor;
- MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.backgroundColor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ layer.backgroundColor = constantExpression;
mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getBackgroundColor(), propertyValue,
- @"Setting backgroundColor to a constant value should update background-color.");
- XCTAssertEqualObjects(layer.backgroundColor, constantStyleValue,
- @"backgroundColor should round-trip constant values.");
-
- MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.backgroundColor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ @"Setting backgroundColor to a constant value expression should update background-color.");
+ XCTAssertEqualObjects(layer.backgroundColor, constantExpression,
+ @"backgroundColor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.backgroundColor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = {{
+ { -INFINITY, { 1, 0, 0, 1 } },
+ { 18, { 1, 0, 0, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
XCTAssertEqual(rawLayer->getBackgroundColor(), propertyValue,
- @"Setting backgroundColor to a camera function should update background-color.");
- XCTAssertEqualObjects(layer.backgroundColor, functionStyleValue,
- @"backgroundColor should round-trip camera functions.");
+ @"Setting backgroundColor to a camera expression should update background-color.");
+ XCTAssertEqualObjects(layer.backgroundColor, functionExpression,
+ @"backgroundColor should round-trip camera expressions.");
layer.backgroundColor = nil;
XCTAssertTrue(rawLayer->getBackgroundColor().isUndefined(),
@"Unsetting backgroundColor should return background-color to the default value.");
- XCTAssertEqualObjects(layer.backgroundColor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.backgroundColor, defaultExpression,
@"backgroundColor should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.backgroundColor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.backgroundColor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.backgroundColor = functionExpression, NSException, NSInvalidArgumentException, @"MGLBackgroundLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.backgroundColor = functionExpression, NSException, NSInvalidArgumentException, @"MGLBackgroundLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
// Transition property test
layer.backgroundColorTransition = transitionTest;
auto toptions = rawLayer->getBackgroundColorTransition();
@@ -79,39 +84,44 @@
{
XCTAssertTrue(rawLayer->getBackgroundOpacity().isUndefined(),
@"background-opacity should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.backgroundOpacity;
+ NSExpression *defaultExpression = layer.backgroundOpacity;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.backgroundOpacity = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.backgroundOpacity = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getBackgroundOpacity(), propertyValue,
- @"Setting backgroundOpacity to a constant value should update background-opacity.");
- XCTAssertEqualObjects(layer.backgroundOpacity, constantStyleValue,
- @"backgroundOpacity should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.backgroundOpacity = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting backgroundOpacity to a constant value expression should update background-opacity.");
+ XCTAssertEqualObjects(layer.backgroundOpacity, constantExpression,
+ @"backgroundOpacity should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.backgroundOpacity = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getBackgroundOpacity(), propertyValue,
- @"Setting backgroundOpacity to a camera function should update background-opacity.");
- XCTAssertEqualObjects(layer.backgroundOpacity, functionStyleValue,
- @"backgroundOpacity should round-trip camera functions.");
+ @"Setting backgroundOpacity to a camera expression should update background-opacity.");
+ XCTAssertEqualObjects(layer.backgroundOpacity, functionExpression,
+ @"backgroundOpacity should round-trip camera expressions.");
layer.backgroundOpacity = nil;
XCTAssertTrue(rawLayer->getBackgroundOpacity().isUndefined(),
@"Unsetting backgroundOpacity should return background-opacity to the default value.");
- XCTAssertEqualObjects(layer.backgroundOpacity, defaultStyleValue,
+ XCTAssertEqualObjects(layer.backgroundOpacity, defaultExpression,
@"backgroundOpacity should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.backgroundOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.backgroundOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.backgroundOpacity = functionExpression, NSException, NSInvalidArgumentException, @"MGLBackgroundLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.backgroundOpacity = functionExpression, NSException, NSInvalidArgumentException, @"MGLBackgroundLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
// Transition property test
layer.backgroundOpacityTransition = transitionTest;
auto toptions = rawLayer->getBackgroundOpacityTransition();
@@ -127,39 +137,44 @@
{
XCTAssertTrue(rawLayer->getBackgroundPattern().isUndefined(),
@"background-pattern should be unset initially.");
- MGLStyleValue<NSString *> *defaultStyleValue = layer.backgroundPattern;
+ NSExpression *defaultExpression = layer.backgroundPattern;
- MGLStyleValue<NSString *> *constantStyleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Background Pattern"];
- layer.backgroundPattern = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'Background Pattern'"];
+ layer.backgroundPattern = constantExpression;
mbgl::style::PropertyValue<std::string> propertyValue = { "Background Pattern" };
XCTAssertEqual(rawLayer->getBackgroundPattern(), propertyValue,
- @"Setting backgroundPattern to a constant value should update background-pattern.");
- XCTAssertEqualObjects(layer.backgroundPattern, constantStyleValue,
- @"backgroundPattern should round-trip constant values.");
-
- MGLStyleValue<NSString *> * functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.backgroundPattern = functionStyleValue;
-
- mbgl::style::IntervalStops<std::string> intervalStops = { {{18, "Background Pattern"}} };
+ @"Setting backgroundPattern to a constant value expression should update background-pattern.");
+ XCTAssertEqualObjects(layer.backgroundPattern, constantExpression,
+ @"backgroundPattern should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'Background Pattern'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.backgroundPattern = functionExpression;
+
+ mbgl::style::IntervalStops<std::string> intervalStops = {{
+ { -INFINITY, "Background Pattern" },
+ { 18, "Background Pattern" },
+ }};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
XCTAssertEqual(rawLayer->getBackgroundPattern(), propertyValue,
- @"Setting backgroundPattern to a camera function should update background-pattern.");
- XCTAssertEqualObjects(layer.backgroundPattern, functionStyleValue,
- @"backgroundPattern should round-trip camera functions.");
+ @"Setting backgroundPattern to a camera expression should update background-pattern.");
+ XCTAssertEqualObjects(layer.backgroundPattern, functionExpression,
+ @"backgroundPattern should round-trip camera expressions.");
layer.backgroundPattern = nil;
XCTAssertTrue(rawLayer->getBackgroundPattern().isUndefined(),
@"Unsetting backgroundPattern should return background-pattern to the default value.");
- XCTAssertEqualObjects(layer.backgroundPattern, defaultStyleValue,
+ XCTAssertEqualObjects(layer.backgroundPattern, defaultExpression,
@"backgroundPattern should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.backgroundPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.backgroundPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.backgroundPattern = functionExpression, NSException, NSInvalidArgumentException, @"MGLBackgroundLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.backgroundPattern = functionExpression, NSException, NSInvalidArgumentException, @"MGLBackgroundLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
// Transition property test
layer.backgroundPatternTransition = transitionTest;
auto toptions = rawLayer->getBackgroundPatternTransition();
diff --git a/platform/darwin/test/MGLCircleStyleLayerTests.mm b/platform/darwin/test/MGLCircleStyleLayerTests.mm
index c0c503153a..d7bf2a5afd 100644
--- a/platform/darwin/test/MGLCircleStyleLayerTests.mm
+++ b/platform/darwin/test/MGLCircleStyleLayerTests.mm
@@ -30,8 +30,8 @@
XCTAssertNil(layer.sourceLayerIdentifier);
XCTAssertNil(layer.predicate);
- layer.predicate = [NSPredicate predicateWithValue:NO];
- XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
+ layer.predicate = [NSPredicate predicateWithFormat:@"$featureIdentifier = 1"];
+ XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithFormat:@"$featureIdentifier = 1"]);
layer.predicate = nil;
XCTAssertNil(layer.predicate);
}
@@ -52,40 +52,45 @@
{
XCTAssertTrue(rawLayer->getCircleBlur().isUndefined(),
@"circle-blur should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleBlur;
+ NSExpression *defaultExpression = layer.circleBlur;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.circleBlur = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.circleBlur = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue,
- @"Setting circleBlur to a constant value should update circle-blur.");
- XCTAssertEqualObjects(layer.circleBlur, constantStyleValue,
- @"circleBlur should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.circleBlur = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting circleBlur to a constant value expression should update circle-blur.");
+ XCTAssertEqualObjects(layer.circleBlur, constantExpression,
+ @"circleBlur should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.circleBlur = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue,
- @"Setting circleBlur to a camera function should update circle-blur.");
- XCTAssertEqualObjects(layer.circleBlur, functionStyleValue,
- @"circleBlur should round-trip camera functions.");
+ @"Setting circleBlur to a camera expression should update circle-blur.");
+ XCTAssertEqualObjects(layer.circleBlur, functionExpression,
+ @"circleBlur should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.circleBlur = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.circleBlur = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue,
- @"Setting circleBlur to a source function should update circle-blur.");
- XCTAssertEqualObjects(layer.circleBlur, functionStyleValue,
- @"circleBlur should round-trip source functions.");
+ @"Setting circleBlur to a data expression should update circle-blur.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.circleBlur, pedanticFunctionExpression,
+ @"circleBlur should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.circleBlur = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.circleBlur = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -93,15 +98,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue,
- @"Setting circleBlur to a composite function should update circle-blur.");
- XCTAssertEqualObjects(layer.circleBlur, functionStyleValue,
- @"circleBlur should round-trip composite functions.");
+ @"Setting circleBlur to a camera-data expression should update circle-blur.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.circleBlur, pedanticFunctionExpression,
+ @"circleBlur should round-trip camera-data expressions.");
layer.circleBlur = nil;
XCTAssertTrue(rawLayer->getCircleBlur().isUndefined(),
@"Unsetting circleBlur should return circle-blur to the default value.");
- XCTAssertEqualObjects(layer.circleBlur, defaultStyleValue,
+ XCTAssertEqualObjects(layer.circleBlur, defaultExpression,
@"circleBlur should return the default value after being unset.");
// Transition property test
layer.circleBlurTransition = transitionTest;
@@ -118,40 +124,45 @@
{
XCTAssertTrue(rawLayer->getCircleColor().isUndefined(),
@"circle-color should be unset initially.");
- MGLStyleValue<MGLColor *> *defaultStyleValue = layer.circleColor;
+ NSExpression *defaultExpression = layer.circleColor;
- MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.circleColor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ layer.circleColor = constantExpression;
mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getCircleColor(), propertyValue,
- @"Setting circleColor to a constant value should update circle-color.");
- XCTAssertEqualObjects(layer.circleColor, constantStyleValue,
- @"circleColor should round-trip constant values.");
-
- MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.circleColor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ @"Setting circleColor to a constant value expression should update circle-color.");
+ XCTAssertEqualObjects(layer.circleColor, constantExpression,
+ @"circleColor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.circleColor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = {{
+ { -INFINITY, { 1, 0, 0, 1 } },
+ { 18, { 1, 0, 0, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
XCTAssertEqual(rawLayer->getCircleColor(), propertyValue,
- @"Setting circleColor to a camera function should update circle-color.");
- XCTAssertEqualObjects(layer.circleColor, functionStyleValue,
- @"circleColor should round-trip camera functions.");
+ @"Setting circleColor to a camera expression should update circle-color.");
+ XCTAssertEqualObjects(layer.circleColor, functionExpression,
+ @"circleColor should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.circleColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.circleColor = functionExpression;
mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getCircleColor(), propertyValue,
- @"Setting circleColor to a source function should update circle-color.");
- XCTAssertEqualObjects(layer.circleColor, functionStyleValue,
- @"circleColor should round-trip source functions.");
+ @"Setting circleColor to a data expression should update circle-color.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.circleColor, pedanticFunctionExpression,
+ @"circleColor should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.circleColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.circleColor = functionExpression;
std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -159,15 +170,16 @@
propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getCircleColor(), propertyValue,
- @"Setting circleColor to a composite function should update circle-color.");
- XCTAssertEqualObjects(layer.circleColor, functionStyleValue,
- @"circleColor should round-trip composite functions.");
+ @"Setting circleColor to a camera-data expression should update circle-color.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.circleColor, pedanticFunctionExpression,
+ @"circleColor should round-trip camera-data expressions.");
layer.circleColor = nil;
XCTAssertTrue(rawLayer->getCircleColor().isUndefined(),
@"Unsetting circleColor should return circle-color to the default value.");
- XCTAssertEqualObjects(layer.circleColor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.circleColor, defaultExpression,
@"circleColor should return the default value after being unset.");
// Transition property test
layer.circleColorTransition = transitionTest;
@@ -184,40 +196,45 @@
{
XCTAssertTrue(rawLayer->getCircleOpacity().isUndefined(),
@"circle-opacity should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleOpacity;
+ NSExpression *defaultExpression = layer.circleOpacity;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.circleOpacity = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.circleOpacity = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue,
- @"Setting circleOpacity to a constant value should update circle-opacity.");
- XCTAssertEqualObjects(layer.circleOpacity, constantStyleValue,
- @"circleOpacity should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.circleOpacity = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting circleOpacity to a constant value expression should update circle-opacity.");
+ XCTAssertEqualObjects(layer.circleOpacity, constantExpression,
+ @"circleOpacity should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.circleOpacity = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue,
- @"Setting circleOpacity to a camera function should update circle-opacity.");
- XCTAssertEqualObjects(layer.circleOpacity, functionStyleValue,
- @"circleOpacity should round-trip camera functions.");
+ @"Setting circleOpacity to a camera expression should update circle-opacity.");
+ XCTAssertEqualObjects(layer.circleOpacity, functionExpression,
+ @"circleOpacity should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.circleOpacity = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.circleOpacity = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue,
- @"Setting circleOpacity to a source function should update circle-opacity.");
- XCTAssertEqualObjects(layer.circleOpacity, functionStyleValue,
- @"circleOpacity should round-trip source functions.");
+ @"Setting circleOpacity to a data expression should update circle-opacity.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.circleOpacity, pedanticFunctionExpression,
+ @"circleOpacity should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.circleOpacity = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.circleOpacity = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -225,15 +242,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue,
- @"Setting circleOpacity to a composite function should update circle-opacity.");
- XCTAssertEqualObjects(layer.circleOpacity, functionStyleValue,
- @"circleOpacity should round-trip composite functions.");
+ @"Setting circleOpacity to a camera-data expression should update circle-opacity.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.circleOpacity, pedanticFunctionExpression,
+ @"circleOpacity should round-trip camera-data expressions.");
layer.circleOpacity = nil;
XCTAssertTrue(rawLayer->getCircleOpacity().isUndefined(),
@"Unsetting circleOpacity should return circle-opacity to the default value.");
- XCTAssertEqualObjects(layer.circleOpacity, defaultStyleValue,
+ XCTAssertEqualObjects(layer.circleOpacity, defaultExpression,
@"circleOpacity should return the default value after being unset.");
// Transition property test
layer.circleOpacityTransition = transitionTest;
@@ -250,79 +268,89 @@
{
XCTAssertTrue(rawLayer->getCirclePitchAlignment().isUndefined(),
@"circle-pitch-alignment should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.circlePitchAlignment;
+ NSExpression *defaultExpression = layer.circlePitchAlignment;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLCirclePitchAlignment:MGLCirclePitchAlignmentViewport]];
- layer.circlePitchAlignment = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ layer.circlePitchAlignment = constantExpression;
mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Viewport };
XCTAssertEqual(rawLayer->getCirclePitchAlignment(), propertyValue,
- @"Setting circlePitchAlignment to a constant value should update circle-pitch-alignment.");
- XCTAssertEqualObjects(layer.circlePitchAlignment, constantStyleValue,
- @"circlePitchAlignment should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.circlePitchAlignment = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = { {{18, mbgl::style::AlignmentType::Viewport}} };
+ @"Setting circlePitchAlignment to a constant value expression should update circle-pitch-alignment.");
+ XCTAssertEqualObjects(layer.circlePitchAlignment, constantExpression,
+ @"circlePitchAlignment should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.circlePitchAlignment = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = {{
+ { -INFINITY, mbgl::style::AlignmentType::Viewport },
+ { 18, mbgl::style::AlignmentType::Viewport },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
XCTAssertEqual(rawLayer->getCirclePitchAlignment(), propertyValue,
- @"Setting circlePitchAlignment to a camera function should update circle-pitch-alignment.");
- XCTAssertEqualObjects(layer.circlePitchAlignment, functionStyleValue,
- @"circlePitchAlignment should round-trip camera functions.");
+ @"Setting circlePitchAlignment to a camera expression should update circle-pitch-alignment.");
+ XCTAssertEqualObjects(layer.circlePitchAlignment, functionExpression,
+ @"circlePitchAlignment should round-trip camera expressions.");
layer.circlePitchAlignment = nil;
XCTAssertTrue(rawLayer->getCirclePitchAlignment().isUndefined(),
@"Unsetting circlePitchAlignment should return circle-pitch-alignment to the default value.");
- XCTAssertEqualObjects(layer.circlePitchAlignment, defaultStyleValue,
+ XCTAssertEqualObjects(layer.circlePitchAlignment, defaultExpression,
@"circlePitchAlignment should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.circlePitchAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.circlePitchAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.circlePitchAlignment = functionExpression, NSException, NSInvalidArgumentException, @"MGLCircleLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.circlePitchAlignment = functionExpression, NSException, NSInvalidArgumentException, @"MGLCircleLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// circle-radius
{
XCTAssertTrue(rawLayer->getCircleRadius().isUndefined(),
@"circle-radius should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleRadius;
+ NSExpression *defaultExpression = layer.circleRadius;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.circleRadius = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.circleRadius = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue,
- @"Setting circleRadius to a constant value should update circle-radius.");
- XCTAssertEqualObjects(layer.circleRadius, constantStyleValue,
- @"circleRadius should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.circleRadius = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting circleRadius to a constant value expression should update circle-radius.");
+ XCTAssertEqualObjects(layer.circleRadius, constantExpression,
+ @"circleRadius should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.circleRadius = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue,
- @"Setting circleRadius to a camera function should update circle-radius.");
- XCTAssertEqualObjects(layer.circleRadius, functionStyleValue,
- @"circleRadius should round-trip camera functions.");
+ @"Setting circleRadius to a camera expression should update circle-radius.");
+ XCTAssertEqualObjects(layer.circleRadius, functionExpression,
+ @"circleRadius should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.circleRadius = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.circleRadius = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue,
- @"Setting circleRadius to a source function should update circle-radius.");
- XCTAssertEqualObjects(layer.circleRadius, functionStyleValue,
- @"circleRadius should round-trip source functions.");
+ @"Setting circleRadius to a data expression should update circle-radius.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.circleRadius, pedanticFunctionExpression,
+ @"circleRadius should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.circleRadius = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.circleRadius = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -330,15 +358,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue,
- @"Setting circleRadius to a composite function should update circle-radius.");
- XCTAssertEqualObjects(layer.circleRadius, functionStyleValue,
- @"circleRadius should round-trip composite functions.");
+ @"Setting circleRadius to a camera-data expression should update circle-radius.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.circleRadius, pedanticFunctionExpression,
+ @"circleRadius should round-trip camera-data expressions.");
layer.circleRadius = nil;
XCTAssertTrue(rawLayer->getCircleRadius().isUndefined(),
@"Unsetting circleRadius should return circle-radius to the default value.");
- XCTAssertEqualObjects(layer.circleRadius, defaultStyleValue,
+ XCTAssertEqualObjects(layer.circleRadius, defaultExpression,
@"circleRadius should return the default value after being unset.");
// Transition property test
layer.circleRadiusTransition = transitionTest;
@@ -355,79 +384,89 @@
{
XCTAssertTrue(rawLayer->getCirclePitchScale().isUndefined(),
@"circle-pitch-scale should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.circleScaleAlignment;
+ NSExpression *defaultExpression = layer.circleScaleAlignment;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentViewport]];
- layer.circleScaleAlignment = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ layer.circleScaleAlignment = constantExpression;
mbgl::style::PropertyValue<mbgl::style::CirclePitchScaleType> propertyValue = { mbgl::style::CirclePitchScaleType::Viewport };
XCTAssertEqual(rawLayer->getCirclePitchScale(), propertyValue,
- @"Setting circleScaleAlignment to a constant value should update circle-pitch-scale.");
- XCTAssertEqualObjects(layer.circleScaleAlignment, constantStyleValue,
- @"circleScaleAlignment should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.circleScaleAlignment = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::CirclePitchScaleType> intervalStops = { {{18, mbgl::style::CirclePitchScaleType::Viewport}} };
+ @"Setting circleScaleAlignment to a constant value expression should update circle-pitch-scale.");
+ XCTAssertEqualObjects(layer.circleScaleAlignment, constantExpression,
+ @"circleScaleAlignment should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.circleScaleAlignment = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::CirclePitchScaleType> intervalStops = {{
+ { -INFINITY, mbgl::style::CirclePitchScaleType::Viewport },
+ { 18, mbgl::style::CirclePitchScaleType::Viewport },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::CirclePitchScaleType> { intervalStops };
XCTAssertEqual(rawLayer->getCirclePitchScale(), propertyValue,
- @"Setting circleScaleAlignment to a camera function should update circle-pitch-scale.");
- XCTAssertEqualObjects(layer.circleScaleAlignment, functionStyleValue,
- @"circleScaleAlignment should round-trip camera functions.");
+ @"Setting circleScaleAlignment to a camera expression should update circle-pitch-scale.");
+ XCTAssertEqualObjects(layer.circleScaleAlignment, functionExpression,
+ @"circleScaleAlignment should round-trip camera expressions.");
layer.circleScaleAlignment = nil;
XCTAssertTrue(rawLayer->getCirclePitchScale().isUndefined(),
@"Unsetting circleScaleAlignment should return circle-pitch-scale to the default value.");
- XCTAssertEqualObjects(layer.circleScaleAlignment, defaultStyleValue,
+ XCTAssertEqualObjects(layer.circleScaleAlignment, defaultExpression,
@"circleScaleAlignment should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.circleScaleAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.circleScaleAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.circleScaleAlignment = functionExpression, NSException, NSInvalidArgumentException, @"MGLCircleLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.circleScaleAlignment = functionExpression, NSException, NSInvalidArgumentException, @"MGLCircleLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// circle-stroke-color
{
XCTAssertTrue(rawLayer->getCircleStrokeColor().isUndefined(),
@"circle-stroke-color should be unset initially.");
- MGLStyleValue<MGLColor *> *defaultStyleValue = layer.circleStrokeColor;
+ NSExpression *defaultExpression = layer.circleStrokeColor;
- MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.circleStrokeColor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ layer.circleStrokeColor = constantExpression;
mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue,
- @"Setting circleStrokeColor to a constant value should update circle-stroke-color.");
- XCTAssertEqualObjects(layer.circleStrokeColor, constantStyleValue,
- @"circleStrokeColor should round-trip constant values.");
-
- MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.circleStrokeColor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ @"Setting circleStrokeColor to a constant value expression should update circle-stroke-color.");
+ XCTAssertEqualObjects(layer.circleStrokeColor, constantExpression,
+ @"circleStrokeColor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.circleStrokeColor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = {{
+ { -INFINITY, { 1, 0, 0, 1 } },
+ { 18, { 1, 0, 0, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue,
- @"Setting circleStrokeColor to a camera function should update circle-stroke-color.");
- XCTAssertEqualObjects(layer.circleStrokeColor, functionStyleValue,
- @"circleStrokeColor should round-trip camera functions.");
+ @"Setting circleStrokeColor to a camera expression should update circle-stroke-color.");
+ XCTAssertEqualObjects(layer.circleStrokeColor, functionExpression,
+ @"circleStrokeColor should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.circleStrokeColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.circleStrokeColor = functionExpression;
mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue,
- @"Setting circleStrokeColor to a source function should update circle-stroke-color.");
- XCTAssertEqualObjects(layer.circleStrokeColor, functionStyleValue,
- @"circleStrokeColor should round-trip source functions.");
+ @"Setting circleStrokeColor to a data expression should update circle-stroke-color.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.circleStrokeColor, pedanticFunctionExpression,
+ @"circleStrokeColor should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.circleStrokeColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.circleStrokeColor = functionExpression;
std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -435,15 +474,16 @@
propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue,
- @"Setting circleStrokeColor to a composite function should update circle-stroke-color.");
- XCTAssertEqualObjects(layer.circleStrokeColor, functionStyleValue,
- @"circleStrokeColor should round-trip composite functions.");
+ @"Setting circleStrokeColor to a camera-data expression should update circle-stroke-color.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.circleStrokeColor, pedanticFunctionExpression,
+ @"circleStrokeColor should round-trip camera-data expressions.");
layer.circleStrokeColor = nil;
XCTAssertTrue(rawLayer->getCircleStrokeColor().isUndefined(),
@"Unsetting circleStrokeColor should return circle-stroke-color to the default value.");
- XCTAssertEqualObjects(layer.circleStrokeColor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.circleStrokeColor, defaultExpression,
@"circleStrokeColor should return the default value after being unset.");
// Transition property test
layer.circleStrokeColorTransition = transitionTest;
@@ -460,40 +500,45 @@
{
XCTAssertTrue(rawLayer->getCircleStrokeOpacity().isUndefined(),
@"circle-stroke-opacity should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleStrokeOpacity;
+ NSExpression *defaultExpression = layer.circleStrokeOpacity;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.circleStrokeOpacity = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.circleStrokeOpacity = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue,
- @"Setting circleStrokeOpacity to a constant value should update circle-stroke-opacity.");
- XCTAssertEqualObjects(layer.circleStrokeOpacity, constantStyleValue,
- @"circleStrokeOpacity should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.circleStrokeOpacity = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting circleStrokeOpacity to a constant value expression should update circle-stroke-opacity.");
+ XCTAssertEqualObjects(layer.circleStrokeOpacity, constantExpression,
+ @"circleStrokeOpacity should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.circleStrokeOpacity = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue,
- @"Setting circleStrokeOpacity to a camera function should update circle-stroke-opacity.");
- XCTAssertEqualObjects(layer.circleStrokeOpacity, functionStyleValue,
- @"circleStrokeOpacity should round-trip camera functions.");
+ @"Setting circleStrokeOpacity to a camera expression should update circle-stroke-opacity.");
+ XCTAssertEqualObjects(layer.circleStrokeOpacity, functionExpression,
+ @"circleStrokeOpacity should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.circleStrokeOpacity = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.circleStrokeOpacity = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue,
- @"Setting circleStrokeOpacity to a source function should update circle-stroke-opacity.");
- XCTAssertEqualObjects(layer.circleStrokeOpacity, functionStyleValue,
- @"circleStrokeOpacity should round-trip source functions.");
+ @"Setting circleStrokeOpacity to a data expression should update circle-stroke-opacity.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.circleStrokeOpacity, pedanticFunctionExpression,
+ @"circleStrokeOpacity should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.circleStrokeOpacity = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.circleStrokeOpacity = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -501,15 +546,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue,
- @"Setting circleStrokeOpacity to a composite function should update circle-stroke-opacity.");
- XCTAssertEqualObjects(layer.circleStrokeOpacity, functionStyleValue,
- @"circleStrokeOpacity should round-trip composite functions.");
+ @"Setting circleStrokeOpacity to a camera-data expression should update circle-stroke-opacity.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.circleStrokeOpacity, pedanticFunctionExpression,
+ @"circleStrokeOpacity should round-trip camera-data expressions.");
layer.circleStrokeOpacity = nil;
XCTAssertTrue(rawLayer->getCircleStrokeOpacity().isUndefined(),
@"Unsetting circleStrokeOpacity should return circle-stroke-opacity to the default value.");
- XCTAssertEqualObjects(layer.circleStrokeOpacity, defaultStyleValue,
+ XCTAssertEqualObjects(layer.circleStrokeOpacity, defaultExpression,
@"circleStrokeOpacity should return the default value after being unset.");
// Transition property test
layer.circleStrokeOpacityTransition = transitionTest;
@@ -526,40 +572,45 @@
{
XCTAssertTrue(rawLayer->getCircleStrokeWidth().isUndefined(),
@"circle-stroke-width should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleStrokeWidth;
+ NSExpression *defaultExpression = layer.circleStrokeWidth;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.circleStrokeWidth = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.circleStrokeWidth = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue,
- @"Setting circleStrokeWidth to a constant value should update circle-stroke-width.");
- XCTAssertEqualObjects(layer.circleStrokeWidth, constantStyleValue,
- @"circleStrokeWidth should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.circleStrokeWidth = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting circleStrokeWidth to a constant value expression should update circle-stroke-width.");
+ XCTAssertEqualObjects(layer.circleStrokeWidth, constantExpression,
+ @"circleStrokeWidth should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.circleStrokeWidth = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue,
- @"Setting circleStrokeWidth to a camera function should update circle-stroke-width.");
- XCTAssertEqualObjects(layer.circleStrokeWidth, functionStyleValue,
- @"circleStrokeWidth should round-trip camera functions.");
+ @"Setting circleStrokeWidth to a camera expression should update circle-stroke-width.");
+ XCTAssertEqualObjects(layer.circleStrokeWidth, functionExpression,
+ @"circleStrokeWidth should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.circleStrokeWidth = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.circleStrokeWidth = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue,
- @"Setting circleStrokeWidth to a source function should update circle-stroke-width.");
- XCTAssertEqualObjects(layer.circleStrokeWidth, functionStyleValue,
- @"circleStrokeWidth should round-trip source functions.");
+ @"Setting circleStrokeWidth to a data expression should update circle-stroke-width.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.circleStrokeWidth, pedanticFunctionExpression,
+ @"circleStrokeWidth should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.circleStrokeWidth = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.circleStrokeWidth = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -567,15 +618,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue,
- @"Setting circleStrokeWidth to a composite function should update circle-stroke-width.");
- XCTAssertEqualObjects(layer.circleStrokeWidth, functionStyleValue,
- @"circleStrokeWidth should round-trip composite functions.");
+ @"Setting circleStrokeWidth to a camera-data expression should update circle-stroke-width.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.circleStrokeWidth, pedanticFunctionExpression,
+ @"circleStrokeWidth should round-trip camera-data expressions.");
layer.circleStrokeWidth = nil;
XCTAssertTrue(rawLayer->getCircleStrokeWidth().isUndefined(),
@"Unsetting circleStrokeWidth should return circle-stroke-width to the default value.");
- XCTAssertEqualObjects(layer.circleStrokeWidth, defaultStyleValue,
+ XCTAssertEqualObjects(layer.circleStrokeWidth, defaultExpression,
@"circleStrokeWidth should return the default value after being unset.");
// Transition property test
layer.circleStrokeWidthTransition = transitionTest;
@@ -592,84 +644,94 @@
{
XCTAssertTrue(rawLayer->getCircleTranslate().isUndefined(),
@"circle-translate should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.circleTranslation;
+ NSExpression *defaultExpression = layer.circleTranslation;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@",
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
- layer.circleTranslation = constantStyleValue;
+ layer.circleTranslation = constantExpression;
mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getCircleTranslate(), propertyValue,
- @"Setting circleTranslation to a constant value should update circle-translate.");
- XCTAssertEqualObjects(layer.circleTranslation, constantStyleValue,
- @"circleTranslation should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.circleTranslation = functionStyleValue;
-
- mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} };
+ @"Setting circleTranslation to a constant value expression should update circle-translate.");
+ XCTAssertEqualObjects(layer.circleTranslation, constantExpression,
+ @"circleTranslation should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"{1, 1}"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.circleTranslation = functionExpression;
+
+ mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = {{
+ { -INFINITY, { 1, 1 } },
+ { 18, { 1, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
XCTAssertEqual(rawLayer->getCircleTranslate(), propertyValue,
- @"Setting circleTranslation to a camera function should update circle-translate.");
- XCTAssertEqualObjects(layer.circleTranslation, functionStyleValue,
- @"circleTranslation should round-trip camera functions.");
+ @"Setting circleTranslation to a camera expression should update circle-translate.");
+ XCTAssertEqualObjects(layer.circleTranslation, functionExpression,
+ @"circleTranslation should round-trip camera expressions.");
layer.circleTranslation = nil;
XCTAssertTrue(rawLayer->getCircleTranslate().isUndefined(),
@"Unsetting circleTranslation should return circle-translate to the default value.");
- XCTAssertEqualObjects(layer.circleTranslation, defaultStyleValue,
+ XCTAssertEqualObjects(layer.circleTranslation, defaultExpression,
@"circleTranslation should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.circleTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.circleTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.circleTranslation = functionExpression, NSException, NSInvalidArgumentException, @"MGLCircleLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.circleTranslation = functionExpression, NSException, NSInvalidArgumentException, @"MGLCircleLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// circle-translate-anchor
{
XCTAssertTrue(rawLayer->getCircleTranslateAnchor().isUndefined(),
@"circle-translate-anchor should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.circleTranslationAnchor;
+ NSExpression *defaultExpression = layer.circleTranslationAnchor;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLCircleTranslationAnchor:MGLCircleTranslationAnchorViewport]];
- layer.circleTranslationAnchor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ layer.circleTranslationAnchor = constantExpression;
mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
XCTAssertEqual(rawLayer->getCircleTranslateAnchor(), propertyValue,
- @"Setting circleTranslationAnchor to a constant value should update circle-translate-anchor.");
- XCTAssertEqualObjects(layer.circleTranslationAnchor, constantStyleValue,
- @"circleTranslationAnchor should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.circleTranslationAnchor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} };
+ @"Setting circleTranslationAnchor to a constant value expression should update circle-translate-anchor.");
+ XCTAssertEqualObjects(layer.circleTranslationAnchor, constantExpression,
+ @"circleTranslationAnchor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.circleTranslationAnchor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = {{
+ { -INFINITY, mbgl::style::TranslateAnchorType::Viewport },
+ { 18, mbgl::style::TranslateAnchorType::Viewport },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
XCTAssertEqual(rawLayer->getCircleTranslateAnchor(), propertyValue,
- @"Setting circleTranslationAnchor to a camera function should update circle-translate-anchor.");
- XCTAssertEqualObjects(layer.circleTranslationAnchor, functionStyleValue,
- @"circleTranslationAnchor should round-trip camera functions.");
+ @"Setting circleTranslationAnchor to a camera expression should update circle-translate-anchor.");
+ XCTAssertEqualObjects(layer.circleTranslationAnchor, functionExpression,
+ @"circleTranslationAnchor should round-trip camera expressions.");
layer.circleTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getCircleTranslateAnchor().isUndefined(),
@"Unsetting circleTranslationAnchor should return circle-translate-anchor to the default value.");
- XCTAssertEqualObjects(layer.circleTranslationAnchor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.circleTranslationAnchor, defaultExpression,
@"circleTranslationAnchor should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.circleTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.circleTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.circleTranslationAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLCircleLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.circleTranslationAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLCircleLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
}
diff --git a/platform/darwin/test/MGLComputedShapeSourceTests.m b/platform/darwin/test/MGLComputedShapeSourceTests.m
new file mode 100644
index 0000000000..6eb45913d6
--- /dev/null
+++ b/platform/darwin/test/MGLComputedShapeSourceTests.m
@@ -0,0 +1,24 @@
+#import <XCTest/XCTest.h>
+
+#import <Mapbox/Mapbox.h>
+
+
+@interface MGLComputedShapeSourceTests : XCTestCase
+@end
+
+@implementation MGLComputedShapeSourceTests
+
+- (void)testInitializer {
+ MGLComputedShapeSource *source = [[MGLComputedShapeSource alloc] initWithIdentifier:@"id" options:@{}];
+ XCTAssertNotNil(source);
+ XCTAssertNotNil(source.requestQueue);
+ XCTAssertNil(source.dataSource);
+}
+
+- (void)testNilOptions {
+ MGLComputedShapeSource *source = [[MGLComputedShapeSource alloc] initWithIdentifier:@"id" options:nil];
+ XCTAssertNotNil(source);
+}
+
+
+@end
diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift
index 668e5f57f8..9edb33a078 100644
--- a/platform/darwin/test/MGLDocumentationExampleTests.swift
+++ b/platform/darwin/test/MGLDocumentationExampleTests.swift
@@ -73,14 +73,14 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
XCTAssertNotNil(mapView.style?.source(withIdentifier: "lines"))
}
- func testMGLRasterSource() {
+ func testMGLRasterTileSource() {
//#-example-code
- 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)
@@ -88,14 +88,34 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
XCTAssertNotNil(mapView.style?.source(withIdentifier: "clouds"))
}
+
+ func testMGLRasterDEMSource() {
+ // We want to use mapbox.terrain-rgb in the example, but using a mapbox:
+ // URL requires setting an access token. So this identically named
+ // subclass of MGLRasterDEMSource swaps in a nonexistent URL.
+ class MGLRasterDEMSource: Mapbox.MGLRasterDEMSource {
+ override init(identifier: String, configurationURL: URL, tileSize: CGFloat = 256) {
+ let bogusURL = URL(string: "https://example.com/raster-rgb.json")!
+ super.init(identifier: identifier, configurationURL: bogusURL, tileSize: tileSize)
+ }
+ }
+
+ //#-example-code
+ let terrainRGBURL = URL(string: "mapbox://mapbox.terrain-rgb")!
+ let source = MGLRasterDEMSource(identifier: "hills", configurationURL: terrainRGBURL)
+ mapView.style?.addSource(source)
+ //#-end-example-code
+
+ XCTAssertNotNil(mapView.style?.source(withIdentifier: "hills"))
+ }
- func testMGLVectorSource() {
+ func testMGLVectorTileSource() {
//#-example-code
- 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)
@@ -131,18 +151,21 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
}
func testMGLCircleStyleLayer() {
- let population = MGLVectorSource(identifier: "population", configurationURL: URL(string: "https://example.com/style.json")!)
+ let population = MGLVectorTileSource(identifier: "population", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style?.addSource(population)
//#-example-code
let layer = MGLCircleStyleLayer(identifier: "circles", source: population)
layer.sourceLayerIdentifier = "population"
- layer.circleColor = MGLStyleValue(rawValue: .green)
- layer.circleRadius = MGLStyleValue(interpolationMode: .exponential,
- cameraStops: [12: MGLStyleValue(rawValue: 2),
- 22: MGLStyleValue(rawValue: 180)],
- options: [.interpolationBase: 1.75])
- layer.circleOpacity = MGLStyleValue(rawValue: 0.7)
+ #if os(macOS)
+ layer.circleColor = NSExpression(forConstantValue: NSColor.green)
+ #else
+ layer.circleColor = NSExpression(forConstantValue: UIColor.green)
+ #endif
+ layer.circleRadius = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'exponential', 1.75, %@)",
+ [12: 2,
+ 22: 180])
+ layer.circleOpacity = NSExpression(forConstantValue: 0.7)
layer.predicate = NSPredicate(format: "%K == %@", "marital-status", "married")
mapView.style?.addLayer(layer)
//#-end-example-code
@@ -151,18 +174,21 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
}
func testMGLLineStyleLayer() {
- let trails = MGLVectorSource(identifier: "trails", configurationURL: URL(string: "https://example.com/style.json")!)
+ let trails = MGLVectorTileSource(identifier: "trails", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style?.addSource(trails)
//#-example-code
let layer = MGLLineStyleLayer(identifier: "trails-path", source: trails)
layer.sourceLayerIdentifier = "trails"
- layer.lineWidth = MGLStyleValue(interpolationMode: .exponential,
- cameraStops: [14: MGLStyleValue(rawValue: 2),
- 18: MGLStyleValue(rawValue: 20)],
- options: [.interpolationBase: 1.5])
- layer.lineColor = MGLStyleValue(rawValue: .brown)
- layer.lineCap = MGLStyleValue(rawValue: NSValue(mglLineCap: .round))
+ layer.lineWidth = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'exponential', 1.5, %@)",
+ [14: 2,
+ 18: 20])
+ #if os(macOS)
+ layer.lineColor = NSExpression(forConstantValue: NSColor.brown)
+ #else
+ layer.lineColor = NSExpression(forConstantValue: UIColor.brown)
+ #endif
+ layer.lineCap = NSExpression(forConstantValue: "round")
layer.predicate = NSPredicate(format: "%K == %@", "trail-type", "mountain-biking")
mapView.style?.addLayer(layer)
//#-end-example-code
@@ -171,13 +197,17 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
}
func testMGLFillStyleLayer() {
- let parks = MGLVectorSource(identifier: "parks", configurationURL: URL(string: "https://example.com/style.json")!)
+ let parks = MGLVectorTileSource(identifier: "parks", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style?.addSource(parks)
//#-example-code
let layer = MGLFillStyleLayer(identifier: "parks", source: parks)
layer.sourceLayerIdentifier = "parks"
- layer.fillColor = MGLStyleValue(rawValue: .green)
+ #if os(macOS)
+ layer.fillColor = NSExpression(forConstantValue: NSColor.green)
+ #else
+ layer.fillColor = NSExpression(forConstantValue: UIColor.green)
+ #endif
layer.predicate = NSPredicate(format: "type == %@", "national-park")
mapView.style?.addLayer(layer)
//#-end-example-code
@@ -186,39 +216,57 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
}
func testMGLFillExtrusionStyleLayer() {
- let buildings = MGLVectorSource(identifier: "buildings", configurationURL: URL(string: "https://example.com/style.json")!)
+ let buildings = MGLVectorTileSource(identifier: "buildings", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style?.addSource(buildings)
//#-example-code
let layer = MGLFillExtrusionStyleLayer(identifier: "buildings", source: buildings)
layer.sourceLayerIdentifier = "building"
- layer.fillExtrusionHeight = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "height", options: nil)
- layer.fillExtrusionBase = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "min_height", options: nil)
+ layer.fillExtrusionHeight = NSExpression(forKeyPath: "height")
+ layer.fillExtrusionBase = NSExpression(forKeyPath: "min_height")
layer.predicate = NSPredicate(format: "extrude == 'true'")
mapView.style?.addLayer(layer)
//#-end-example-code
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "buildings"))
}
+
+ func testMGLHeatmapStyleLayer() {
+ let earthquakes = MGLShapeSource(identifier: "earthquakes", url: URL(string: "https://example.com/earthquakes.json")!, options: [:])
+ mapView.style?.addSource(earthquakes)
+
+ //#-example-code
+ let layer = MGLHeatmapStyleLayer(identifier: "earthquake-heat", source: earthquakes)
+ layer.heatmapWeight = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:(magnitude, 'linear', nil, %@)",
+ [0: 0,
+ 6: 1])
+ layer.heatmapIntensity = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)",
+ [0: 1,
+ 9: 3])
+ mapView.style?.addLayer(layer)
+ //#-end-example-code
+
+ XCTAssertNotNil(mapView.style?.layer(withIdentifier: "earthquake-heat"))
+ }
func testMGLSymbolStyleLayer() {
- let pois = MGLVectorSource(identifier: "pois", configurationURL: URL(string: "https://example.com/style.json")!)
+ let pois = MGLVectorTileSource(identifier: "pois", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style?.addSource(pois)
//#-example-code
let layer = MGLSymbolStyleLayer(identifier: "coffeeshops", source: pois)
layer.sourceLayerIdentifier = "pois"
- layer.iconImageName = MGLStyleValue(rawValue: "coffee")
- layer.iconScale = MGLStyleValue(rawValue: 0.5)
- layer.text = MGLStyleValue(rawValue: "{name}")
+ layer.iconImageName = NSExpression(forConstantValue: "coffee")
+ layer.iconScale = NSExpression(forConstantValue: 0.5)
+ layer.text = NSExpression(forKeyPath: "name")
#if os(macOS)
var vector = CGVector(dx: 10, dy: 0)
- layer.textTranslation = MGLStyleValue(rawValue: NSValue(bytes: &vector, objCType: "{CGVector=dd}"))
+ layer.textTranslation = NSExpression(forConstantValue: NSValue(bytes: &vector, objCType: "{CGVector=dd}"))
#else
- layer.textTranslation = MGLStyleValue(rawValue: NSValue(cgVector: CGVector(dx: 10, dy: 0)))
+ layer.textTranslation = NSExpression(forConstantValue: NSValue(cgVector: CGVector(dx: 10, dy: 0)))
#endif
- layer.textJustification = MGLStyleValue(rawValue: NSValue(mglTextJustification: .left))
- layer.textAnchor = MGLStyleValue(rawValue: NSValue(mglTextAnchor: .left))
+ layer.textJustification = NSExpression(forConstantValue: "left")
+ layer.textAnchor = NSExpression(forConstantValue: "left")
layer.predicate = NSPredicate(format: "%K == %@", "venue-type", "coffee")
mapView.style?.addLayer(layer)
//#-end-example-code
@@ -227,33 +275,60 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
}
func testMGLRasterStyleLayer() {
- 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)
//#-example-code
let layer = MGLRasterStyleLayer(identifier: "clouds", source: source)
- layer.rasterOpacity = MGLStyleValue(rawValue: 0.5)
+ layer.rasterOpacity = NSExpression(forConstantValue: 0.5)
mapView.style?.addLayer(layer)
//#-end-example-code
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "clouds"))
}
+ func testMGLHillshadeStyleLayer() {
+ let source = MGLRasterDEMSource(identifier: "dem", tileURLTemplates: ["https://example.com/raster-rgb/{z}/{x}/{y}.png"], options: [
+ .minimumZoomLevel: 9,
+ .maximumZoomLevel: 16,
+ .tileSize: 256,
+ .attributionInfos: [
+ MGLAttributionInfo(title: NSAttributedString(string: "© Mapbox"), url: URL(string: "https://mapbox.com"))
+ ]
+ ])
+ mapView.style?.addSource(source)
+
+ let canals = MGLVectorTileSource(identifier: "canals", configurationURL: URL(string: "https://example.com/style.json")!)
+ mapView.style?.addSource(canals)
+ let canalShadowLayer = MGLLineStyleLayer(identifier: "waterway-river-canal-shadow", source: canals)
+ mapView.style?.addLayer(canalShadowLayer)
+
+ //#-example-code
+ let layer = MGLHillshadeStyleLayer(identifier: "hills", source: source)
+ layer.hillshadeExaggeration = NSExpression(forConstantValue: 0.6)
+ if let canalShadowLayer = mapView.style?.layer(withIdentifier: "waterway-river-canal-shadow") {
+ mapView.style?.insertLayer(layer, below: canalShadowLayer)
+ }
+ //#-end-example-code
+
+ XCTAssertNotNil(mapView.style?.layer(withIdentifier: "hills"))
+ }
+
func testMGLVectorStyleLayer$predicate() {
- let terrain = MGLVectorSource(identifier: "terrain", configurationURL: URL(string: "https://example.com/style.json")!)
+ let terrain = MGLVectorTileSource(identifier: "terrain", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style?.addSource(terrain)
//#-example-code
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)
//#-end-example-code
@@ -295,7 +370,7 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
#endif
class MGLStyle {
- static func satelliteStreetsStyleURL() -> URL {
+ static var satelliteStreetsStyleURL: URL {
return MGLDocumentationExampleTests.styleURL
}
}
@@ -303,7 +378,7 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
//#-example-code
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)
@@ -316,7 +391,7 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
}
//#-end-example-code
- wait(for: [expectation], timeout: 1)
+ wait(for: [expectation], timeout: 5)
}
// For testMGLMapView().
diff --git a/platform/darwin/test/MGLDocumentationGuideTests.swift b/platform/darwin/test/MGLDocumentationGuideTests.swift
index c71f1b46c7..4de1d81aa9 100644
--- a/platform/darwin/test/MGLDocumentationGuideTests.swift
+++ b/platform/darwin/test/MGLDocumentationGuideTests.swift
@@ -1,3 +1,4 @@
+import XCTest
import Foundation
import Mapbox
#if os(iOS)
@@ -49,31 +50,32 @@ class MGLDocumentationGuideTests: XCTestCase, MGLMapViewDelegate {
styleLoadingExpectation.fulfill()
}
- func testUsingStyleFunctionsAtRuntime$Stops() {
+ func testMigratingToExpressions$Stops() {
//#-example-code
#if os(macOS)
- let stops = [
- 0: MGLStyleValue<NSColor>(rawValue: .yellow),
- 2.5: MGLStyleValue(rawValue: .orange),
- 5: MGLStyleValue(rawValue: .red),
- 7.5: MGLStyleValue(rawValue: .blue),
- 10: MGLStyleValue(rawValue: .white),
+ let stops: [NSNumber: NSColor] = [
+ 0: .yellow,
+ 2.5: .orange,
+ 5: .red,
+ 7.5: .blue,
+ 10: .white,
]
#else
- let stops = [
- 0: MGLStyleValue<UIColor>(rawValue: .yellow),
- 2.5: MGLStyleValue(rawValue: .orange),
- 5: MGLStyleValue(rawValue: .red),
- 7.5: MGLStyleValue(rawValue: .blue),
- 10: MGLStyleValue(rawValue: .white),
+ let stops: [NSNumber: UIColor] = [
+ 0: .yellow,
+ 2.5: .orange,
+ 5: .red,
+ 7.5: .blue,
+ 10: .white,
]
#endif
//#-end-example-code
- let _ = MGLStyleValue(interpolationMode: .exponential, cameraStops: stops, options: nil)
+ let _ = NSExpression(format: "mgl_step:from:stops:(mag, %@, %@)",
+ stops[0]!, stops)
}
- func testUsingStyleFunctionsAtRuntime$Linear() {
+ func testMigratingToExpressions$Linear() {
//#-example-code
let url = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson")!
let symbolSource = MGLSource(identifier: "source")
@@ -83,132 +85,192 @@ class MGLDocumentationGuideTests: XCTestCase, MGLMapViewDelegate {
mapView.style?.addSource(source)
#if os(macOS)
- let stops = [
- 0: MGLStyleValue<NSColor>(rawValue: .yellow),
- 2.5: MGLStyleValue(rawValue: .orange),
- 5: MGLStyleValue(rawValue: .red),
- 7.5: MGLStyleValue(rawValue: .blue),
- 10: MGLStyleValue(rawValue: .white),
+ let stops: [NSNumber: NSColor] = [
+ 0: .yellow,
+ 2.5: .orange,
+ 5: .red,
+ 7.5: .blue,
+ 10: .white,
]
#else
- let stops = [
- 0: MGLStyleValue<UIColor>(rawValue: .yellow),
- 2.5: MGLStyleValue(rawValue: .orange),
- 5: MGLStyleValue(rawValue: .red),
- 7.5: MGLStyleValue(rawValue: .blue),
- 10: MGLStyleValue(rawValue: .white),
+ let stops: [NSNumber: UIColor] = [
+ 0: .yellow,
+ 2.5: .orange,
+ 5: .red,
+ 7.5: .blue,
+ 10: .white,
]
#endif
let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
#if os(macOS)
- layer.circleColor = MGLStyleValue(interpolationMode: .exponential,
- sourceStops: stops,
- attributeName: "mag",
- options: [.defaultValue: MGLStyleValue<NSColor>(rawValue: .green)])
+ layer.circleColor = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:(mag, 'linear', nil, %@)",
+ stops)
#else
- layer.circleColor = MGLStyleValue(interpolationMode: .exponential,
- sourceStops: stops,
- attributeName: "mag",
- options: [.defaultValue: MGLStyleValue<UIColor>(rawValue: .green)])
+ layer.circleColor = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:(mag, 'linear', nil, %@)",
+ stops)
#endif
- layer.circleRadius = MGLStyleValue(rawValue: 10)
+ layer.circleRadius = NSExpression(forConstantValue: 10)
mapView.style?.insertLayer(layer, below: symbolLayer)
//#-end-example-code
}
- func testUsingStyleFunctionsAtRuntime$Exponential() {
+ func testMigratingToExpressions$LinearConvenience() {
+ let source = MGLShapeSource(identifier: "circles", shape: nil, options: nil)
+ let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
+
+ #if os(macOS)
+ let stops: [NSNumber: NSColor] = [
+ 0: .yellow,
+ 2.5: .orange,
+ 5: .red,
+ 7.5: .blue,
+ 10: .white,
+ ]
+ #else
+ let stops: [NSNumber: UIColor] = [
+ 0: .yellow,
+ 2.5: .orange,
+ 5: .red,
+ 7.5: .blue,
+ 10: .white,
+ ]
+ #endif
+
+ //#-example-code
+ layer.circleColor = NSExpression(forMGLInterpolating: NSExpression(forKeyPath: "mag"), curveType: .linear, parameters: nil, stops: NSExpression(forConstantValue: stops))
+ //#-end-example-code
+
+ layer.circleRadius = NSExpression(forConstantValue: 10)
+ mapView.style?.addLayer(layer)
+
+ }
+ func testMigratingToExpressions$Exponential() {
let source = MGLShapeSource(identifier: "circles", shape: nil, options: nil)
let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
//#-example-code
let stops = [
- 12: MGLStyleValue<NSNumber>(rawValue: 0.5),
- 14: MGLStyleValue(rawValue: 2),
- 18: MGLStyleValue(rawValue: 18),
+ 12: 0.5,
+ 14: 2,
+ 18: 18,
]
- layer.circleRadius = MGLStyleValue(interpolationMode: .exponential,
- cameraStops: stops,
- options: [.interpolationBase: 1.5])
+ layer.circleRadius = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'exponential', 1.5, %@)",
+ stops)
//#-end-example-code
}
- func testUsingStyleFunctionsAtRuntime$Interval() {
+ func testMigratingToExpressions$ExponentialConvenience() {
+ let source = MGLShapeSource(identifier: "circles", shape: nil, options: nil)
+ let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
+
+ //#-example-code
+ let stops = [
+ 12: 0.5,
+ 14: 2,
+ 18: 18,
+ ]
+
+ layer.circleRadius = NSExpression(forMGLInterpolating: NSExpression.zoomLevelVariable, curveType: MGLExpressionInterpolationMode.exponential, parameters: NSExpression(forConstantValue: 1.5), stops: NSExpression(forConstantValue: stops))
+ //#-end-example-code
+ }
+ func testMigratingToExpressions$Interval() {
let source = MGLShapeSource(identifier: "circles", shape: nil, options: nil)
let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
//#-example-code
#if os(macOS)
- let stops = [
- 0: MGLStyleValue<NSColor>(rawValue: .yellow),
- 2.5: MGLStyleValue(rawValue: .orange),
- 5: MGLStyleValue(rawValue: .red),
- 7.5: MGLStyleValue(rawValue: .blue),
- 10: MGLStyleValue(rawValue: .white),
+ let stops: [NSNumber: NSColor] = [
+ 0: .yellow,
+ 2.5: .orange,
+ 5: .red,
+ 7.5: .blue,
+ 10: .white,
]
- layer.circleColor = MGLStyleValue(interpolationMode: .interval,
- sourceStops: stops,
- attributeName: "mag",
- options: [.defaultValue: MGLStyleValue<NSColor>(rawValue: .green)])
+ layer.circleColor = NSExpression(format: "mgl_step:from:stops:(mag, %@, %@)",
+ NSColor.green, stops)
#else
- let stops = [
- 0: MGLStyleValue<UIColor>(rawValue: .yellow),
- 2.5: MGLStyleValue(rawValue: .orange),
- 5: MGLStyleValue(rawValue: .red),
- 7.5: MGLStyleValue(rawValue: .blue),
- 10: MGLStyleValue(rawValue: .white),
+ let stops: [NSNumber: UIColor] = [
+ 0: .yellow,
+ 2.5: .orange,
+ 5: .red,
+ 7.5: .blue,
+ 10: .white,
]
- layer.circleColor = MGLStyleValue(interpolationMode: .interval,
- sourceStops: stops,
- attributeName: "mag",
- options: [.defaultValue: MGLStyleValue<UIColor>(rawValue: .green)])
+ layer.circleColor = NSExpression(format: "mgl_step:from:stops:(mag, %@, %@)",
+ UIColor.green, stops)
#endif
//#-end-example-code
}
- func testUsingStyleFunctionsAtRuntime$Categorical() {
+ func testMigratingToExpressions$Categorical() {
let source = MGLShapeSource(identifier: "circles", shape: nil, options: nil)
let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
//#-example-code
#if os(macOS)
- let categoricalStops = [
- "earthquake": MGLStyleValue<NSColor>(rawValue: .orange),
- "explosion": MGLStyleValue(rawValue: .red),
- "quarry blast": MGLStyleValue(rawValue: .yellow),
- ]
-
- layer.circleColor = MGLStyleValue(interpolationMode: .categorical,
- sourceStops: categoricalStops,
- attributeName: "type",
- options: [.defaultValue: MGLStyleValue<NSColor>(rawValue: .blue)])
+ let defaultColor = NSColor.blue
+ layer.circleColor = NSExpression(
+ format: "MGL_MATCH(type, 'earthquake', %@, 'explosion', %@, 'quarry blast', %@, %@)",
+ NSColor.orange, NSColor.red, NSColor.yellow, defaultColor)
#else
- let categoricalStops = [
- "earthquake": MGLStyleValue<UIColor>(rawValue: .orange),
- "explosion": MGLStyleValue(rawValue: .red),
- "quarry blast": MGLStyleValue(rawValue: .yellow),
- ]
-
- layer.circleColor = MGLStyleValue(interpolationMode: .categorical,
- sourceStops: categoricalStops,
- attributeName: "type",
- options: [.defaultValue: MGLStyleValue<UIColor>(rawValue: .blue)])
+ let defaultColor = UIColor.blue
+ layer.circleColor = NSExpression(format: "MGL_MATCH(type, 'earthquake', %@, 'explosion', %@, 'quarry blast', %@, %@)",
+ UIColor.orange, UIColor.red, UIColor.yellow, defaultColor)
+ #endif
+ //#-end-example-code
+ }
+
+ func testMigratingToExpressions$CategoricalValue() {
+ let source = MGLShapeSource(identifier: "circles", shape: nil, options: nil)
+ let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
+
+ //#-example-code
+ #if os(macOS)
+ let stops : [String : NSColor] = ["earthquake" : NSColor.orange,
+ "explosion" : NSColor.red,
+ "quarry blast" : NSColor.yellow]
+ layer.circleColor = NSExpression(
+ format: "FUNCTION(%@, 'valueForKeyPath:', type)",
+ stops)
+ #else
+ let stops : [String : UIColor] = ["earthquake" : UIColor.orange,
+ "explosion" : UIColor.red,
+ "quarry blast" : UIColor.yellow]
+ layer.circleColor = NSExpression(
+ format: "FUNCTION(%@, 'valueForKeyPath:', type)",
+ stops)
#endif
//#-end-example-code
}
+ func testMigratingToExpressions$Identity() {
+ let source = MGLShapeSource(identifier: "circles", shape: nil, options: nil)
+ let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
+
+ //#-example-code
+ layer.circleRadius = NSExpression(forKeyPath: "mag")
+ //#-end-example-code
+ }
- func testUsingStyleFunctionsAtRuntime$Identity() {
+ func testMigratingToExpressions$Multiply() {
let source = MGLShapeSource(identifier: "circles", shape: nil, options: nil)
let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
//#-example-code
- layer.circleRadius = MGLStyleValue(interpolationMode: .identity,
- sourceStops: nil,
- attributeName: "mag",
- options: [.defaultValue: MGLStyleValue<NSNumber>(rawValue: 0)])
+ layer.circleRadius = NSExpression(forFunction: "multiply:by:", arguments: [NSExpression(forKeyPath: "mag"), 3])
+ //#-end-example-code
+ }
+
+ func testMigratingToExpressions$Cast() {
+ let source = MGLShapeSource(identifier: "circles", shape: nil, options: nil)
+
+ //#-example-code
+ let magnitudeLayer = MGLSymbolStyleLayer(identifier: "mag-layer", source: source)
+ magnitudeLayer.text = NSExpression(format: "CAST(mag, 'NSString')")
+ mapView.style?.addLayer(magnitudeLayer)
//#-end-example-code
}
}
diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm
index ad0833a068..6d710fdcfe 100644
--- a/platform/darwin/test/MGLExpressionTests.mm
+++ b/platform/darwin/test/MGLExpressionTests.mm
@@ -1,9 +1,17 @@
#import <XCTest/XCTest.h>
+#import "MGLStyleLayerTests.h"
+
#import <string>
#import "MGLTypes.h"
-#import "NSExpression+MGLAdditions.h"
+#import "NSExpression+MGLPrivateAdditions.h"
+#import "NSValue+MGLAdditions.h"
+#if TARGET_OS_IPHONE
+#import "UIColor+MGLAdditions.h"
+#else
+#import "NSColor+MGLAdditions.h"
+#endif
#define MGLAssertEqualValues(actual, expected, ...) \
XCTAssertTrue(actual.is<__typeof__(expected)>()); \
@@ -17,11 +25,14 @@
XCTAssertEqualWithAccuracy(actual.get<__typeof__(expected)>(), expected, accuracy, __VA_ARGS__); \
}
+#define MGLConstantExpression(constant) \
+ [NSExpression expressionForConstantValue:constant]
+
#define MGLAssertConstantEqualsValue(constant, value, ...) \
- MGLAssertEqualValues([NSExpression expressionForConstantValue:constant].mgl_constantMBGLValue, value, __VA_ARGS__);
+ MGLAssertEqualValues(MGLConstantExpression(constant).mgl_constantMBGLValue, value, __VA_ARGS__);
#define MGLAssertConstantEqualsValueWithAccuracy(constant, value, accuracy, ...) \
- MGLAssertEqualValuesWithAccuracy([NSExpression expressionForConstantValue:constant].mgl_constantMBGLValue, value, accuracy, __VA_ARGS__);
+ MGLAssertEqualValuesWithAccuracy(MGLConstantExpression(constant).mgl_constantMBGLValue, value, accuracy, __VA_ARGS__);
using namespace std::string_literals;
@@ -140,4 +151,942 @@ using namespace std::string_literals;
XCTAssertEqual([NSExpression expressionForConstantValue:nil].mgl_featureType, mbgl::FeatureType::Unknown);
}
+#pragma mark - JSON expression object tests
+
+- (void)testVariableExpressionObject {
+ {
+ NSExpression *expression = [NSExpression expressionForVariable:@"zoomLevel"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, @[@"zoom"]);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"$zoomLevel"].mgl_jsonExpressionObject, @[@"zoom"]);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:@[@"zoom"]], expression);
+ NSMutableDictionary *context = [@{@"zoomLevel": @16} mutableCopy];
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:context], @16);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForVariable:@"heatmapDensity"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, @[@"heatmap-density"]);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"$heatmapDensity"].mgl_jsonExpressionObject, @[@"heatmap-density"]);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:@[@"heatmap-density"]], expression);
+ NSMutableDictionary *context = [@{@"heatmapDensity": @1} mutableCopy];
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:context], @1);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForVariable:@"geometryType"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, @[@"geometry-type"]);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"$geometryType"].mgl_jsonExpressionObject, @[@"geometry-type"]);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:@[@"geometry-type"]], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForVariable:@"featureIdentifier"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, @[@"id"]);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"$featureIdentifier"].mgl_jsonExpressionObject, @[@"id"]);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:@[@"id"]], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForVariable:@"featureAttributes"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, @[@"properties"]);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"$featureAttributes"].mgl_jsonExpressionObject, @[@"properties"]);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:@[@"properties"]], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForVariable:@"loremIpsum"];
+ NSArray *jsonExpression = @[@"var", @"loremIpsum"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"$loremIpsum"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ NSMutableDictionary *context = [@{@"loremIpsum": @"Lorem ipsum dolor sit amet"} mutableCopy];
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:context], @"Lorem ipsum dolor sit amet");
+ }
+ {
+ NSDictionary *context = @{@"loremIpsum": MGLConstantExpression(@"Lorem ipsum dolor sit amet")};
+ NSExpression *expression = [NSExpression expressionWithFormat:@"MGL_LET('loremIpsum', 'Lorem ipsum dolor sit amet', uppercase($loremIpsum))", context];
+ NSExpression *compatibilityExpression = [NSExpression expressionWithFormat:@"FUNCTION(uppercase($loremIpsum), 'mgl_expressionWithContext:', %@)", context];
+ NSArray *jsonExpression = @[@"let", @"loremIpsum", @"Lorem ipsum dolor sit amet", @[@"upcase", @[@"var", @"loremIpsum"]]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+}
+
+- (void)testConstantValueExpressionObject {
+ {
+ NSExpression *expression = [NSExpression expressionForConstantValue:nil];
+ XCTAssert(expression.mgl_jsonExpressionObject == [NSNull null]);
+ XCTAssert([NSExpression expressionWithFormat:@"nil"].mgl_jsonExpressionObject == [NSNull null]);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:[NSNull null]], expression);
+ XCTAssertNil([expression expressionValueWithObject:nil context:nil]);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForConstantValue:@1];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, @1);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"1"].mgl_jsonExpressionObject, @1);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:@1], expression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @1);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForConstantValue:@YES];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, @YES);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"TRUE"].mgl_jsonExpressionObject, @YES);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:@YES], expression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @YES);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForConstantValue:nil];
+ XCTAssert(expression.mgl_jsonExpressionObject == [NSNull null]);
+ XCTAssert([NSExpression expressionWithFormat:@"nil"].mgl_jsonExpressionObject == [NSNull null]);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:[NSNull null]], expression);
+ XCTAssertNil([expression expressionValueWithObject:nil context:nil]);
+ }
+ {
+ CGVector vector = CGVectorMake(1, 2);
+ NSExpression *expression = [NSExpression expressionForConstantValue:@(vector)];
+#if !TARGET_OS_IPHONE
+ NSArray *jsonExpression = @[@"literal", @[@1, @-2]];
+#else
+ NSArray *jsonExpression = @[@"literal", @[@1, @2]];
+#endif
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ // No way to distinguish offsets from ordinary arrays in expressions.
+ XCTAssertEqualObjects([[NSExpression expressionWithMGLJSONObject:jsonExpression].collection valueForKeyPath:@"constantValue"], jsonExpression.lastObject);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @(vector));
+ }
+ {
+#if !TARGET_OS_IPHONE
+ NSEdgeInsets padding = {1, 2, 3, 4};
+ NSValue *value = [NSValue valueWithEdgeInsets:padding];
+#else
+ UIEdgeInsets padding = {1, 2, 3, 4};
+ NSValue *value = [NSValue valueWithUIEdgeInsets:padding];
+#endif
+ NSExpression *expression = [NSExpression expressionForConstantValue:value];
+ NSArray *jsonExpression = @[@"literal", @[@1, @4, @3, @2]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ // No way to distinguish offsets from ordinary arrays in expressions.
+ XCTAssertEqualObjects([[NSExpression expressionWithMGLJSONObject:jsonExpression].collection valueForKeyPath:@"constantValue"], jsonExpression.lastObject);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], value);
+ }
+ {
+ MGLColor *color = [MGLColor mgl_colorWithColor:{ 255.0/255, 239.0/255, 213.0/255, 1 }]; // papayawhip
+ NSExpression *expression = [NSExpression expressionForConstantValue:color];
+ NSArray *jsonExpression = @[@"rgb", @255, @239, @213];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], color);
+ }
+ {
+ MGLColor *color = [MGLColor mgl_colorWithColor:{ 255.0/255, 239.0/255, 213.0/255, 0.5 }]; // papayawhip
+ NSExpression *expression = [NSExpression expressionForConstantValue:color];
+ NSArray *jsonExpression = @[@"rgba", @255, @239, @213, @0.5];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], color);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"noindex(513)"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, @513);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @513);
+ }
+}
+
+- (void)testKeyPathExpressionObject {
+ {
+ NSExpression *expression = [NSExpression expressionForKeyPath:@"highway"];
+ NSArray *jsonExpression = @[@"get", @"highway"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"highway"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"%@.population", @{@"population": MGLConstantExpression(@12000)}];
+ NSArray *jsonExpression = @[@"get", @"population", @[@"literal", @{@"population": @12000}]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"%@.uppercase('population')", @{@"POPULATION": MGLConstantExpression(@12000)}];
+ NSArray *jsonExpression = @[@"get", @[@"upcase", @"population"], @[@"literal", @{@"POPULATION": @12000}]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+}
+
+- (void)testStatisticalExpressionObject {
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"average({1, 2, 2, 3, 4, 7, 9})"];
+ NSArray *jsonExpression = @[@"/", @[@"+", @1, @2, @2, @3, @4, @7, @9], @[@"length", @[@"literal", @[@1, @2, @2, @3, @4, @7, @9]]]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @4);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"sum({1, 2, 2, 3, 4, 7, 9})"];
+ NSArray *jsonExpression = @[@"+", @1, @2, @2, @3, @4, @7, @9];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @28);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"count({1, 2, 2, 3, 4, 7, 9})"];
+ NSArray *jsonExpression = @[@"length", @[@"literal", @[@1, @2, @2, @3, @4, @7, @9]]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @7);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"min({1, 2, 2, 3, 4, 7, 9})"];
+ NSArray *jsonExpression = @[@"min", @1, @2, @2, @3, @4, @7, @9];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @1);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"max({1, 2, 2, 3, 4, 7, 9})"];
+ NSArray *jsonExpression = @[@"max", @1, @2, @2, @3, @4, @7, @9];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @9);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+}
+
+- (void)testArithmeticExpressionObject {
+ NSArray *arguments = @[MGLConstantExpression(@1), MGLConstantExpression(@1)];
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"add:to:" arguments:arguments];
+ NSArray *jsonExpression = @[@"+", @1, @1];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"1 + 1"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSArray *arguments = @[MGLConstantExpression(@1), MGLConstantExpression(@1), MGLConstantExpression(@1)];
+ NSExpression *expression = [NSExpression expressionForFunction:@"add:to:" arguments:arguments];
+ NSArray *jsonExpression = @[@"+", @1, @1, @1];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ jsonExpression = @[@"+", @[@"+", @1, @1], @1];
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"1 + 1 + 1"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], [NSExpression expressionWithFormat:@"1 + 1 + 1"]);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"from:subtract:" arguments:arguments];
+ NSArray *jsonExpression = @[@"-", @1, @1];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"1 - 1"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"multiply:by:" arguments:arguments];
+ NSArray *jsonExpression = @[@"*", @1, @1];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"1 * 1"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"divide:by:" arguments:arguments];
+ NSArray *jsonExpression = @[@"/", @1, @1];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"1 / 1"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"modulus:by:" arguments:arguments];
+ NSArray *jsonExpression = @[@"%", @1, @1];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ // NSExpression lacks a shorthand operator for modulus.
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"ceiling:" arguments:@[MGLConstantExpression(@1.5)]];
+ NSArray *jsonExpression = @[@"ceil", @1.5];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @2);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"ceiling:" arguments:@[MGLConstantExpression(@-1.5)]];
+ NSArray *jsonExpression = @[@"ceil", @-1.5];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @-1);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"ceiling:" arguments:@[MGLConstantExpression(@2)]];
+ NSArray *jsonExpression = @[@"ceil", @2];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @2);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"ceiling:" arguments:@[MGLConstantExpression(@-2)]];
+ NSArray *jsonExpression = @[@"ceil", @-2];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @-2);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"trunc:" arguments:@[MGLConstantExpression(@1.5)]];
+ NSArray *jsonExpression = @[@"-", @1.5, @[@"%", @1.5, @1]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @1);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"trunc:" arguments:@[MGLConstantExpression(@-1.5)]];
+ NSArray *jsonExpression = @[@"-", @-1.5, @[@"%", @-1.5, @1]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @-1);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"abs:" arguments:@[MGLConstantExpression(@2)]];
+ NSArray *jsonExpression = @[@"abs", @2];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @2);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"abs:" arguments:@[MGLConstantExpression(@-2)]];
+ NSArray *jsonExpression = @[@"abs", @-2];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @2);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"floor:" arguments:@[MGLConstantExpression(@1.5)]];
+ NSArray *jsonExpression = @[@"floor", @1.5];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @1);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"floor:" arguments:@[MGLConstantExpression(@-1.5)]];
+ NSArray *jsonExpression = @[@"floor", @-1.5];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @-2);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"floor:" arguments:@[MGLConstantExpression(@2)]];
+ NSArray *jsonExpression = @[@"floor", @2];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @2);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"floor:" arguments:@[MGLConstantExpression(@-2)]];
+ NSArray *jsonExpression = @[@"floor", @-2];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @-2);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_round:" arguments:@[MGLConstantExpression(@1.5)]];
+ NSArray *jsonExpression = @[@"round", @1.5];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @2);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_round:" arguments:@[MGLConstantExpression(@-1.5)]];
+ NSArray *jsonExpression = @[@"round", @-1.5];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @-2);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_round:" arguments:@[MGLConstantExpression(@2.5)]];
+ NSArray *jsonExpression = @[@"round", @2.5];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @3);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_round:" arguments:@[MGLConstantExpression(@-2.5)]];
+ NSArray *jsonExpression = @[@"round", @-2.5];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @-3);
+ }
+}
+
+- (void)testTrigonometricExpressionObject {
+ NSArray *arguments = @[MGLConstantExpression(@1), MGLConstantExpression(@1)];
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"sqrt:" arguments:arguments];
+ NSArray *jsonExpression = @[@"sqrt", @1, @1];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"ln:" arguments:arguments];
+ NSArray *jsonExpression = @[@"ln", @1, @1];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_log2:" arguments:@[MGLConstantExpression(@1024)]];
+ NSArray *jsonExpression = @[@"log2", @1024];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @10);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"raise:toPower:" arguments:arguments];
+ NSArray *jsonExpression = @[@"^", @1, @1];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"1 ** 1"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"exp:" arguments:@[MGLConstantExpression(@0)]];
+ NSArray *jsonExpression = @[@"^", @[@"e"], @0];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @1);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForConstantValue:@(M_E)];
+ NSArray *jsonExpression = @[@"e"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @(M_E));
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForConstantValue:@(M_PI)];
+ NSArray *jsonExpression = @[@"pi"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @(M_PI));
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_acos:" arguments:@[MGLConstantExpression(@1)]];
+ NSArray *jsonExpression = @[@"acos", @1];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @0);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_cos:" arguments:@[MGLConstantExpression(@0)]];
+ NSArray *jsonExpression = @[@"cos", @0];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @1);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_asin:" arguments:@[MGLConstantExpression(@0)]];
+ NSArray *jsonExpression = @[@"asin", @0];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @0);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_sin:" arguments:@[MGLConstantExpression(@0)]];
+ NSArray *jsonExpression = @[@"sin", @0];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @0);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_atan:" arguments:@[MGLConstantExpression(@20)]];
+ NSArray *jsonExpression = @[@"atan", @20];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ NSNumber *value = [expression expressionValueWithObject:nil context:nil];
+ XCTAssertEqualWithAccuracy(value.doubleValue, 1.52, 0.001);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_tan:" arguments:@[MGLConstantExpression(@0)]];
+ NSArray *jsonExpression = @[@"tan", @0];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @0);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+}
+
+- (void)testStringFormattingExpressionObject {
+ NSArray *arguments = @[MGLConstantExpression(@"MacDonald")];
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"FUNCTION('Old', 'stringByAppendingString:', 'MacDonald')"];
+ NSExpression *aftermarketExpression = [NSExpression expressionWithFormat:@"mgl_join({'Old', 'MacDonald'})"];
+ NSArray *jsonExpression = @[@"concat", @"Old", @"MacDonald"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects(aftermarketExpression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @"OldMacDonald");
+ XCTAssertEqualObjects([aftermarketExpression expressionValueWithObject:nil context:nil], @"OldMacDonald");
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], aftermarketExpression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"uppercase:" arguments:arguments];
+ NSArray *jsonExpression = @[@"upcase", @"MacDonald"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"lowercase:" arguments:arguments];
+ NSArray *jsonExpression = @[@"downcase", @"MacDonald"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"length:" arguments:arguments];
+ NSArray *jsonExpression = @[@"length", @"MacDonald"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+}
+
+- (void)testTypeConversionExpressionObject {
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"FUNCTION(number, 'boolValue')"];
+ NSArray *jsonExpression = @[@"to-boolean", @[@"get", @"number"]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ // NSExpression is unable to evaluate -[NSNumber boolValue] by itself
+ // because it returns a primitive instead of an object.
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"FUNCTION(postalCode, 'mgl_number')"];
+ NSArray *jsonExpression = @[@"to-number", @[@"get", @"postalCode"]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"FUNCTION(postalCode, 'doubleValue')"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"FUNCTION(postalCode, 'floatValue')"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"FUNCTION(postalCode, 'decimalValue')"].mgl_jsonExpressionObject, jsonExpression);
+ // NSExpression is unable to evaluate NSNumber’s -floatValue,
+ // -doubleValue, or -decimalValue by themselves because they each return
+ // a primitive instead of an object.
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression],
+ [NSExpression expressionWithFormat:@"CAST(postalCode, 'NSNumber')"]);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"FUNCTION(postalCode, 'mgl_numberWithFallbackValues:', zipCode)"];
+ NSArray *jsonExpression = @[@"to-number", @[@"get", @"postalCode"], @[@"get", @"zipCode"]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"FUNCTION(postalCode, 'doubleValue', zipCode)"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"FUNCTION(postalCode, 'floatValue', zipCode)"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"FUNCTION(postalCode, 'decimalValue', zipCode)"].mgl_jsonExpressionObject, jsonExpression);
+ // NSExpression is unable to evaluate NSNumber’s -floatValue,
+ // -doubleValue, or -decimalValue by themselves because they each return
+ // a primitive instead of an object.
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"CAST(postalCode, 'NSNumber')"];
+ NSExpression *compatibilityExpression = [NSExpression expressionWithFormat:@"FUNCTION(postalCode, 'mgl_numberWithFallbackValues:')"];
+ NSArray *jsonExpression = @[@"to-number", @[@"get", @"postalCode"]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:@{@"postalCode": @"02134"} context:nil], @02134);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"CAST(number, 'NSString')"];
+ NSExpression *compatibilityExpression = [NSExpression expressionWithFormat:@"FUNCTION(number, 'stringValue')"];
+ NSArray *jsonExpression = @[@"to-string", @[@"get", @"number"]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:@{@"number": @1.5} context:nil], @"1.5");
+ XCTAssertEqualObjects([compatibilityExpression expressionValueWithObject:@{@"number": @1.5} context:nil], @"1.5");
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+}
+
+- (void)testInterpolationExpressionObject {
+ {
+ NSDictionary *stops = @{@0: MGLConstantExpression(@100), @10: MGLConstantExpression(@200)};
+ NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(x, 'linear', nil, %@)", stops];
+ NSExpression *compatibilityExpression = [NSExpression expressionWithFormat:@"FUNCTION(x, 'mgl_interpolateWithCurveType:parameters:stops:', 'linear', nil, %@)", stops];
+ NSArray *jsonExpression = @[@"interpolate", @[@"linear"], @[@"get", @"x"], @0, @100, @10, @200];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSDictionary *stops = @{@1: MGLConstantExpression(@2), @3: MGLConstantExpression(@6)};
+ NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(x, 'exponential', 2, %@)", stops];
+ NSArray *jsonExpression = @[@"interpolate", @[@"exponential", @2], @[@"get", @"x"], @1, @2, @3, @6];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSDictionary *stops = @{@0: MGLConstantExpression(@0), @100: MGLConstantExpression(@100)};
+ NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(x, 'cubic-bezier', { 0.42, 0, 0.58, 1 }, %@)", stops];
+ NSArray *jsonExpression = @[@"interpolate", @[@"cubic-bezier", @0.42, @0, @0.58, @1], @[@"get", @"x"], @0, @0, @100, @100];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSDictionary *stops = @{@0: MGLConstantExpression(@111), @1: MGLConstantExpression(@1111)};
+ NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(x, 11, %@)", stops];
+ NSExpression *compatibilityExpression = [NSExpression expressionWithFormat:@"FUNCTION(x, 'mgl_stepWithMinimum:stops:', 11, %@)", stops];
+ NSArray *jsonExpression = @[@"step", @[@"get", @"x"], @11, @0, @111, @1, @1111];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSDictionary *stops = @{@0: MGLConstantExpression(@111), @1: MGLConstantExpression(@1111)};
+ NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, 11, %@)", stops];
+ NSArray *jsonExpression = @[@"step", @[@"zoom"], @11, @0, @111, @1, @1111];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+}
+
+- (void)testMatchExpressionObject {
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"MGL_MATCH(2 - 1, %@, %@, %@, %@, 'default')", MGLConstantExpression(@1),
+ MGLConstantExpression(@"one"),
+ MGLConstantExpression(@0),
+ MGLConstantExpression(@"zero")];
+ NSExpression *predicate = [NSExpression expressionWithFormat:@"2 - 1"];
+ NSExpression *compatibilityExpression = [NSExpression expressionWithFormat:@"FUNCTION(%@, 'mgl_match:', %@)", predicate, @[MGLConstantExpression(@1),
+ MGLConstantExpression(@"one"),
+ MGLConstantExpression(@0),
+ MGLConstantExpression(@"zero"),
+ MGLConstantExpression(@"default")]];
+ NSArray *jsonExpression = @[@"match", @[@"-", @2, @1], @1, @"one", @0, @"zero", @"default"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"MGL_MATCH(2 * 1, %@, %@, 'default')", MGLConstantExpression(@1), MGLConstantExpression(@"one")];
+ NSArray *jsonExpression = @[@"match", @[@"*", @2, @1], @1, @"one", @"default"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+}
+
+- (void)testCoalesceExpressionObject {
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_coalesce(%@)",
+ @[[NSExpression expressionForKeyPath:@"x"],
+ [NSExpression expressionForKeyPath:@"y"],
+ [NSExpression expressionForKeyPath:@"z"],
+ [NSExpression expressionForConstantValue:@0]]];
+ NSExpression *compatibilityExpression = [NSExpression expressionWithFormat:@"FUNCTION(%@, 'mgl_coalesce')", @[[NSExpression expressionForKeyPath:@"x"],
+ [NSExpression expressionForKeyPath:@"y"],
+ [NSExpression expressionForKeyPath:@"z"],
+ [NSExpression expressionForConstantValue:@0]]];
+ NSArray *jsonExpression = @[@"coalesce", @[@"get", @"x"], @[@"get", @"y"], @[@"get", @"z"], @0];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+
+}
+
+- (void)testConditionalExpressionObject {
+ {
+ NSPredicate *conditional = [NSPredicate predicateWithFormat:@"1 = 2"];
+ NSExpression *trueExpression = [NSExpression expressionForConstantValue:@YES];
+ NSExpression *falseExpression = [NSExpression expressionForConstantValue:@NO];
+ NSExpression *expression = [NSExpression expressionForConditional:conditional trueExpression:trueExpression falseExpression:falseExpression];
+ NSArray *jsonExpression = @[@"case", @[@"==", @1, @2], @YES, @NO];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"TERNARY(1 = 2, TRUE, FALSE)"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"TERNARY(0 = 1, TRUE, TERNARY(1 = 2, TRUE, FALSE))"];
+ NSArray *jsonExpression = @[@"case", @[@"==", @0, @1], @YES, @[@"==", @1, @2], @YES, @NO];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
+ expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, TRUE, %@, TRUE, FALSE)",
+ MGLConstantExpression([NSPredicate predicateWithFormat:@"0 = 1"]),
+ MGLConstantExpression([NSPredicate predicateWithFormat:@"1 = 2"])];
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, %@, %@)",
+ [NSExpression expressionWithFormat:@"%@", [NSPredicate predicateWithFormat:@"1 = 2"]],
+ MGLConstantExpression(@YES),
+ MGLConstantExpression(@NO)];
+ NSExpression *compatibilityExpression = [NSExpression expressionWithFormat:@"FUNCTION(%@, 'mgl_if:', %@)", [NSPredicate predicateWithFormat:@"1 = 2"], @[MGLConstantExpression(@YES), MGLConstantExpression(@NO)]];
+ NSArray *jsonExpression = @[@"case", @[@"==", @1, @2], @YES, @NO];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, jsonExpression);
+ expression = [NSExpression expressionWithFormat:@"TERNARY(1 = 2, YES, NO)"];
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, %@, %@, %@, %@)",
+ [NSExpression expressionWithFormat:@"%@", [NSPredicate predicateWithFormat:@"1 = 2"]],
+ MGLConstantExpression(@YES),
+ [NSExpression expressionWithFormat:@"%@", [NSPredicate predicateWithFormat:@"1 = 1"]],
+ MGLConstantExpression(@YES),
+ MGLConstantExpression(@NO)];
+ NSArray *jsonExpression = @[@"case", @[@"==", @1, @2], @YES, @[@"==", @1, @1], @YES, @NO];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @YES);
+ }
+ {
+ NSArray *jsonExpression = @[
+ @"case",
+ @[
+ @"<",
+ @[@"get", @"area"],
+ @80000
+ ],
+ @[@"get", @"abbr"],
+ @[@"get", @"name_en"]
+ ];
+ NSExpression *expression = [NSExpression expressionWithFormat:@"TERNARY(area < 80000, abbr, name_en)"];
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ }
+}
+
+- (void)testLookupExpressionObject {
+ {
+ NSExpression *array = [NSExpression expressionForAggregate:@[MGLConstantExpression(@9),
+ MGLConstantExpression(@8),
+ MGLConstantExpression(@7)]];
+ NSExpression *expression = [NSExpression expressionForFunction:@"objectFrom:withIndex:"
+ arguments:@[array, MGLConstantExpression(@1)]];
+ NSArray *jsonExpression = @[@"at", @1, @[ @"literal", @[@9, @8, @7]]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *array = [NSExpression expressionForAggregate:@[MGLConstantExpression(@9),
+ MGLConstantExpression(@8),
+ MGLConstantExpression(@7)]];
+ NSExpression *expression = [NSExpression expressionForFunction:@"objectFrom:withIndex:"
+ arguments:@[array, [NSExpression expressionForKeyPath:@"x"]]];
+ NSArray *jsonExpression = @[@"at", @[@"get", @"x"], @[ @"literal", @[@9, @8, @7]]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_does:have:"
+ arguments:@[[NSExpression expressionForEvaluatedObject],
+ [NSExpression expressionForConstantValue:@"x"]]];
+ NSExpression *compatibilityExpression = [NSExpression expressionWithFormat:@"FUNCTION(self, 'mgl_has:', 'x')"];
+ NSArray *jsonExpression = @[@"has", @"x"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_does:have:"
+ arguments:@[MGLConstantExpression(@{@"x": MGLConstantExpression(@0)}),
+ MGLConstantExpression(@"x")]];
+ NSArray *jsonExpression = @[@"has", @"x", @[@"literal", @{@"x": @0}]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_does:have:"
+ arguments:@[[NSExpression expressionForVariable:@"featureAttributes"],
+ [NSExpression expressionForConstantValue:@"x"]]];
+ NSArray *jsonExpression = @[@"has", @"x", @[@"properties"]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression;
+ expression = [NSExpression expressionWithFormat:@"TERNARY(key != nil, 1, 0)"];
+ NSArray *jsonExpression = @[@"case", @[@"!=", @[@"get", @"key"], [NSNull null]], @1, @0];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:@{} context:nil], @NO);
+ XCTAssertEqualObjects([expression expressionValueWithObject:@{@"key": @"🗝"} context:nil], @YES);
+ }
+ {
+ NSDictionary *dictionary = @{@"key": @"🔑"};
+ NSExpression *expression;
+ expression = [NSExpression expressionWithFormat:@"TERNARY(%@.key != nil, 1, 0)", dictionary];
+ NSArray *jsonExpression = @[@"case", @[@"!=", @[@"get", @"key", @[@"literal", dictionary]], [NSNull null]], @1, @0];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ // The dictionary isn’t equal enough.
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression].description, expression.description);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @YES);
+ }
+}
+
+- (void)testGenericExpressionObject {
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"MGL_FUNCTION('random', 1, 2, 3, 4, 5)"];
+ NSArray *jsonExpression = @[@"random", @1, @2, @3, @4, @5];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ expression = [NSExpression expressionWithFormat:@"MGL_FUNCTION('random', 1, 2, 3, 4)"];
+ XCTAssertThrowsSpecificNamed([expression expressionValueWithObject:nil context:nil], NSException, NSInvalidArgumentException);
+ }
+}
+
+#pragma mark - Localization tests
+
+- (void)testTokenReplacement {
+ {
+ NSExpression *original = MGLConstantExpression(@"");
+ NSExpression *expected = original;
+ XCTAssertEqualObjects(original.mgl_expressionByReplacingTokensWithKeyPaths, expected);
+ }
+ {
+ NSExpression *original = MGLConstantExpression(@"{");
+ NSExpression *expected = original;
+ XCTAssertEqualObjects(original.mgl_expressionByReplacingTokensWithKeyPaths, expected);
+ }
+ {
+ NSExpression *original = MGLConstantExpression(@"{token");
+ NSExpression *expected = original;
+ XCTAssertEqualObjects(original.mgl_expressionByReplacingTokensWithKeyPaths, expected);
+ }
+ {
+ NSExpression *original = MGLConstantExpression(@"{token}");
+ NSExpression *expected = [NSExpression expressionForKeyPath:@"token"];
+ XCTAssertEqualObjects(original.mgl_expressionByReplacingTokensWithKeyPaths, expected);
+ }
+ {
+ NSExpression *original = MGLConstantExpression(@"{token} {token}");
+ NSExpression *expected = [NSExpression expressionWithFormat:@"mgl_join({token, ' ', token})"];
+ XCTAssertEqualObjects(original.mgl_expressionByReplacingTokensWithKeyPaths, expected);
+ }
+ {
+ NSExpression *original = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, '{short}', %@)", @{
+ @1: MGLConstantExpression(@"{short}"),
+ @2: @"…",
+ @3: @"{long}",
+ }];
+ NSExpression *expected = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, short, %@)", @{
+ @1: [NSExpression expressionForKeyPath:@"short"],
+ @2: @"…",
+ @3: [NSExpression expressionForKeyPath:@"long"],
+ }];
+ XCTAssertEqualObjects(original.mgl_expressionByReplacingTokensWithKeyPaths, expected);
+ }
+}
+
+- (void)testLocalization {
+ {
+ NSExpression *original = MGLConstantExpression(@"");
+ NSExpression *expected = original;
+ XCTAssertEqualObjects([original mgl_expressionLocalizedIntoLocale:nil], expected);
+ }
+ {
+ NSExpression *original = MGLConstantExpression(@"Old MacDonald");
+ NSExpression *expected = original;
+ XCTAssertEqualObjects([original mgl_expressionLocalizedIntoLocale:nil], expected);
+ }
+ {
+ NSExpression *original = MGLConstantExpression(@"{name_en}");
+ NSExpression *expected = original;
+ XCTAssertEqualObjects([original mgl_expressionLocalizedIntoLocale:nil], expected);
+ }
+ {
+ NSExpression *original = [NSExpression expressionForKeyPath:@"name_en"];
+ NSExpression *expected = original;
+ XCTAssertEqualObjects([original mgl_expressionLocalizedIntoLocale:nil], expected);
+ }
+ {
+ NSExpression *original = [NSExpression expressionForKeyPath:@"name_en"];
+ NSExpression *expected = [NSExpression expressionForKeyPath:@"name"];
+ XCTAssertEqualObjects([original mgl_expressionLocalizedIntoLocale:[NSLocale localeWithLocaleIdentifier:@"mul"]], expected);
+ }
+ {
+ NSExpression *original = [NSExpression expressionForKeyPath:@"name_en"];
+ NSExpression *expected = [NSExpression expressionForKeyPath:@"name_fr"];
+ XCTAssertEqualObjects([original mgl_expressionLocalizedIntoLocale:[NSLocale localeWithLocaleIdentifier:@"fr-CA"]], expected);
+ }
+ {
+ NSExpression *original = [NSExpression expressionForKeyPath:@"name_en"];
+ NSExpression *expected = [NSExpression expressionForKeyPath:@"name_zh-Hans"];
+ XCTAssertEqualObjects([original mgl_expressionLocalizedIntoLocale:[NSLocale localeWithLocaleIdentifier:@"zh-Hans"]], expected);
+ }
+ {
+ NSExpression *original = [NSExpression expressionForKeyPath:@"name_en"];
+ NSExpression *expected = [NSExpression expressionForKeyPath:@"name"];
+ XCTAssertEqualObjects([original mgl_expressionLocalizedIntoLocale:[NSLocale localeWithLocaleIdentifier:@"tlh"]], expected);
+ }
+ {
+ NSExpression *original = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, short, %@)", @{
+ @1: [NSExpression expressionForKeyPath:@"abbr"],
+ @2: @"…",
+ @3: [NSExpression expressionForKeyPath:@"name_fr"],
+ }];
+ NSExpression *expected = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, short, %@)", @{
+ @1: [NSExpression expressionForKeyPath:@"abbr"],
+ @2: @"…",
+ @3: [NSExpression expressionForKeyPath:@"name_es"],
+ }];
+ XCTAssertEqualObjects([original mgl_expressionLocalizedIntoLocale:[NSLocale localeWithLocaleIdentifier:@"es-PR"]], expected);
+ }
+ {
+ NSArray *jsonExpression = @[
+ @"step",
+ @[@"zoom"],
+ @[
+ @"case",
+ @[
+ @"<",
+ @[
+ @"to-number",
+ @[@"get", @"area"]
+ ],
+ @80000
+ ],
+ @[@"get", @"abbr"],
+ @[@"get", @"name_en"]
+ ],
+ @5, @[@"get", @"name_en"]
+ ];
+ NSArray *localizedJSONExpression = @[
+ @"step",
+ @[@"zoom"],
+ @[
+ @"case",
+ @[
+ @"<",
+ @[
+ @"to-number",
+ @[@"get", @"area"]
+ ],
+ @80000
+ ],
+ @[@"get", @"abbr"],
+ @[@"get", @"name"]
+ ],
+ @5, @[@"get", @"name"]
+ ];
+ NSExpression *expression = [NSExpression expressionWithMGLJSONObject:jsonExpression];
+ NSExpression *localizedExpression = [expression mgl_expressionLocalizedIntoLocale:[NSLocale localeWithLocaleIdentifier:@"mul"]];
+ XCTAssertEqualObjects(localizedExpression.mgl_jsonExpressionObject, localizedJSONExpression);
+ }
+}
+
+- (void)testConvenienceInitializers {
+ {
+ NSExpression *expression = [NSExpression mgl_expressionForConditional:[NSPredicate predicateWithFormat:@"1 = 2"]
+ trueExpression:MGLConstantExpression(@YES)
+ falseExpresssion:MGLConstantExpression(@NO)];
+
+ NSArray *jsonExpression = @[@"case", @[@"==", @1, @2], @YES, @NO];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
+ }
+ {
+ NSDictionary *stops = @{@0: MGLConstantExpression(@111), @1: MGLConstantExpression(@1111)};
+ NSExpression *expression = [NSExpression mgl_expressionForSteppingExpression:[NSExpression expressionForKeyPath:@"x"]
+ fromExpression:[NSExpression expressionForConstantValue:@11]
+ stops:[NSExpression expressionForConstantValue:stops]];
+ NSArray *jsonExpression = @[@"step", @[@"get", @"x"], @11, @0, @111, @1, @1111];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSDictionary *stops = @{@0: MGLConstantExpression(@100), @10: MGLConstantExpression(@200)};
+ NSExpression *expression = [NSExpression mgl_expressionForInterpolatingExpression:[NSExpression expressionForKeyPath:@"x"]
+ withCurveType:MGLExpressionInterpolationModeLinear
+ parameters:nil
+ stops:[NSExpression expressionForConstantValue:stops]];
+ NSArray *jsonExpression = @[@"interpolate", @[@"linear"], @[@"get", @"x"], @0, @100, @10, @200];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [[NSExpression expressionForConstantValue:@"Old"] mgl_expressionByAppendingExpression:[NSExpression expressionForConstantValue:@"MacDonald"]];
+
+ NSArray *jsonExpression = @[@"concat", @"Old", @"MacDonald"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @"OldMacDonald");
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSDictionary *values = @{ MGLConstantExpression(@1): MGLConstantExpression(@"one") };
+ NSExpression *expression = [NSExpression mgl_expressionForMatchingExpression:[NSExpression expressionWithFormat:@"2 * 1"]
+ inDictionary:values
+ defaultExpression:[NSExpression expressionForConstantValue:@"default"]];
+ NSArray *jsonExpression = @[@"match", @[@"*", @2, @1], @1, @"one", @"default"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+}
+
+
@end
diff --git a/platform/darwin/test/MGLFeatureTests.mm b/platform/darwin/test/MGLFeatureTests.mm
index 818ad8200e..d135b018f4 100644
--- a/platform/darwin/test/MGLFeatureTests.mm
+++ b/platform/darwin/test/MGLFeatureTests.mm
@@ -38,7 +38,7 @@
};
features.push_back(mbgl::Feature { polygon });
- NS_ARRAY_OF(MGLShape <MGLFeature> *) *shapes = MGLFeaturesFromMBGLFeatures(features);
+ NSArray<MGLShape <MGLFeature> *> *shapes = MGLFeaturesFromMBGLFeatures(features);
XCTAssertEqual(shapes.count, 3, @"All features should be converted into shapes");
MGLPointFeature *pointShape = (MGLPointFeature *)shapes[0];
@@ -69,7 +69,7 @@
[NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(4, 4)]);
XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:polygonCoordinates[3]],
[NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(4, 1)]);
- NS_ARRAY_OF(MGLPolygon *) *interiorPolygons = polygonShape.interiorPolygons;
+ NSArray<MGLPolygon *> *interiorPolygons = polygonShape.interiorPolygons;
XCTAssertEqual(interiorPolygons.count, 1);
MGLPolygon *interiorPolygon = interiorPolygons.firstObject;
XCTAssertEqual(interiorPolygon.pointCount, 4);
@@ -103,7 +103,7 @@
vector.push_back(true);
features.push_back(pointFeature);
- NS_ARRAY_OF(MGLShape <MGLFeature> *) *shapes = MGLFeaturesFromMBGLFeatures(features);
+ NSArray<MGLShape <MGLFeature> *> *shapes = MGLFeaturesFromMBGLFeatures(features);
XCTAssertEqual(shapes.count, 1, @"All features should be converted into shapes");
MGLShape <MGLFeature> *shape = shapes.firstObject;
@@ -298,29 +298,36 @@
}
- (void)testShapeCollectionFeatureGeoJSONDictionary {
- MGLPointAnnotation *pointFeature = [[MGLPointAnnotation alloc] init];
+ MGLPointFeature *pointFeature = [[MGLPointFeature alloc] init];
CLLocationCoordinate2D pointCoordinate = { 10, 10 };
pointFeature.coordinate = pointCoordinate;
CLLocationCoordinate2D coord1 = { 0, 0 };
CLLocationCoordinate2D coord2 = { 10, 10 };
CLLocationCoordinate2D coords[] = { coord1, coord2 };
- MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coords count:2];
+ MGLPolylineFeature *polylineFeature = [MGLPolylineFeature polylineWithCoordinates:coords count:2];
+
+ MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[pointFeature, polylineFeature]];
- MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[pointFeature,
- polyline]];
// A GeoJSON feature
NSDictionary *geoJSONFeature = [shapeCollectionFeature geoJSONDictionary];
// it has the correct geometry
NSDictionary *expectedGeometry = @{@"type": @"GeometryCollection",
@"geometries": @[
- @{@"type": @"Point",
- @"coordinates": @[@(pointCoordinate.longitude), @(pointCoordinate.latitude)]},
- @{@"type": @"LineString",
- @"coordinates": @[@[@(coord1.longitude), @(coord1.latitude)],
- @[@(coord2.longitude), @(coord2.latitude)]]}
- ]};
+ @{ @"geometry": @{@"type": @"Point",
+ @"coordinates": @[@(pointCoordinate.longitude), @(pointCoordinate.latitude)]},
+ @"properties": [NSNull null],
+ @"type": @"Feature",
+ },
+ @{ @"geometry": @{@"type": @"LineString",
+ @"coordinates": @[@[@(coord1.longitude), @(coord1.latitude)],
+ @[@(coord2.longitude), @(coord2.latitude)]]},
+ @"properties": [NSNull null],
+ @"type": @"Feature",
+ }
+ ]
+ };
XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry);
// When the shape collection is created with an empty array of shapes
diff --git a/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm b/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm
index 5d99c815ea..6081d104e1 100644
--- a/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm
+++ b/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm
@@ -30,8 +30,8 @@
XCTAssertNil(layer.sourceLayerIdentifier);
XCTAssertNil(layer.predicate);
- layer.predicate = [NSPredicate predicateWithValue:NO];
- XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
+ layer.predicate = [NSPredicate predicateWithFormat:@"$featureIdentifier = 1"];
+ XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithFormat:@"$featureIdentifier = 1"]);
layer.predicate = nil;
XCTAssertNil(layer.predicate);
}
@@ -52,40 +52,45 @@
{
XCTAssertTrue(rawLayer->getFillExtrusionBase().isUndefined(),
@"fill-extrusion-base should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillExtrusionBase;
+ NSExpression *defaultExpression = layer.fillExtrusionBase;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.fillExtrusionBase = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.fillExtrusionBase = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getFillExtrusionBase(), propertyValue,
- @"Setting fillExtrusionBase to a constant value should update fill-extrusion-base.");
- XCTAssertEqualObjects(layer.fillExtrusionBase, constantStyleValue,
- @"fillExtrusionBase should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.fillExtrusionBase = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting fillExtrusionBase to a constant value expression should update fill-extrusion-base.");
+ XCTAssertEqualObjects(layer.fillExtrusionBase, constantExpression,
+ @"fillExtrusionBase should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.fillExtrusionBase = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getFillExtrusionBase(), propertyValue,
- @"Setting fillExtrusionBase to a camera function should update fill-extrusion-base.");
- XCTAssertEqualObjects(layer.fillExtrusionBase, functionStyleValue,
- @"fillExtrusionBase should round-trip camera functions.");
+ @"Setting fillExtrusionBase to a camera expression should update fill-extrusion-base.");
+ XCTAssertEqualObjects(layer.fillExtrusionBase, functionExpression,
+ @"fillExtrusionBase should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.fillExtrusionBase = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.fillExtrusionBase = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getFillExtrusionBase(), propertyValue,
- @"Setting fillExtrusionBase to a source function should update fill-extrusion-base.");
- XCTAssertEqualObjects(layer.fillExtrusionBase, functionStyleValue,
- @"fillExtrusionBase should round-trip source functions.");
+ @"Setting fillExtrusionBase to a data expression should update fill-extrusion-base.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.fillExtrusionBase, pedanticFunctionExpression,
+ @"fillExtrusionBase should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.fillExtrusionBase = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.fillExtrusionBase = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -93,15 +98,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getFillExtrusionBase(), propertyValue,
- @"Setting fillExtrusionBase to a composite function should update fill-extrusion-base.");
- XCTAssertEqualObjects(layer.fillExtrusionBase, functionStyleValue,
- @"fillExtrusionBase should round-trip composite functions.");
+ @"Setting fillExtrusionBase to a camera-data expression should update fill-extrusion-base.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.fillExtrusionBase, pedanticFunctionExpression,
+ @"fillExtrusionBase should round-trip camera-data expressions.");
layer.fillExtrusionBase = nil;
XCTAssertTrue(rawLayer->getFillExtrusionBase().isUndefined(),
@"Unsetting fillExtrusionBase should return fill-extrusion-base to the default value.");
- XCTAssertEqualObjects(layer.fillExtrusionBase, defaultStyleValue,
+ XCTAssertEqualObjects(layer.fillExtrusionBase, defaultExpression,
@"fillExtrusionBase should return the default value after being unset.");
// Transition property test
layer.fillExtrusionBaseTransition = transitionTest;
@@ -118,40 +124,45 @@
{
XCTAssertTrue(rawLayer->getFillExtrusionColor().isUndefined(),
@"fill-extrusion-color should be unset initially.");
- MGLStyleValue<MGLColor *> *defaultStyleValue = layer.fillExtrusionColor;
+ NSExpression *defaultExpression = layer.fillExtrusionColor;
- MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.fillExtrusionColor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ layer.fillExtrusionColor = constantExpression;
mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getFillExtrusionColor(), propertyValue,
- @"Setting fillExtrusionColor to a constant value should update fill-extrusion-color.");
- XCTAssertEqualObjects(layer.fillExtrusionColor, constantStyleValue,
- @"fillExtrusionColor should round-trip constant values.");
-
- MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.fillExtrusionColor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ @"Setting fillExtrusionColor to a constant value expression should update fill-extrusion-color.");
+ XCTAssertEqualObjects(layer.fillExtrusionColor, constantExpression,
+ @"fillExtrusionColor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.fillExtrusionColor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = {{
+ { -INFINITY, { 1, 0, 0, 1 } },
+ { 18, { 1, 0, 0, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
XCTAssertEqual(rawLayer->getFillExtrusionColor(), propertyValue,
- @"Setting fillExtrusionColor to a camera function should update fill-extrusion-color.");
- XCTAssertEqualObjects(layer.fillExtrusionColor, functionStyleValue,
- @"fillExtrusionColor should round-trip camera functions.");
+ @"Setting fillExtrusionColor to a camera expression should update fill-extrusion-color.");
+ XCTAssertEqualObjects(layer.fillExtrusionColor, functionExpression,
+ @"fillExtrusionColor should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.fillExtrusionColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.fillExtrusionColor = functionExpression;
mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getFillExtrusionColor(), propertyValue,
- @"Setting fillExtrusionColor to a source function should update fill-extrusion-color.");
- XCTAssertEqualObjects(layer.fillExtrusionColor, functionStyleValue,
- @"fillExtrusionColor should round-trip source functions.");
+ @"Setting fillExtrusionColor to a data expression should update fill-extrusion-color.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.fillExtrusionColor, pedanticFunctionExpression,
+ @"fillExtrusionColor should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.fillExtrusionColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.fillExtrusionColor = functionExpression;
std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -159,15 +170,16 @@
propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getFillExtrusionColor(), propertyValue,
- @"Setting fillExtrusionColor to a composite function should update fill-extrusion-color.");
- XCTAssertEqualObjects(layer.fillExtrusionColor, functionStyleValue,
- @"fillExtrusionColor should round-trip composite functions.");
+ @"Setting fillExtrusionColor to a camera-data expression should update fill-extrusion-color.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.fillExtrusionColor, pedanticFunctionExpression,
+ @"fillExtrusionColor should round-trip camera-data expressions.");
layer.fillExtrusionColor = nil;
XCTAssertTrue(rawLayer->getFillExtrusionColor().isUndefined(),
@"Unsetting fillExtrusionColor should return fill-extrusion-color to the default value.");
- XCTAssertEqualObjects(layer.fillExtrusionColor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.fillExtrusionColor, defaultExpression,
@"fillExtrusionColor should return the default value after being unset.");
// Transition property test
layer.fillExtrusionColorTransition = transitionTest;
@@ -184,40 +196,45 @@
{
XCTAssertTrue(rawLayer->getFillExtrusionHeight().isUndefined(),
@"fill-extrusion-height should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillExtrusionHeight;
+ NSExpression *defaultExpression = layer.fillExtrusionHeight;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.fillExtrusionHeight = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.fillExtrusionHeight = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getFillExtrusionHeight(), propertyValue,
- @"Setting fillExtrusionHeight to a constant value should update fill-extrusion-height.");
- XCTAssertEqualObjects(layer.fillExtrusionHeight, constantStyleValue,
- @"fillExtrusionHeight should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.fillExtrusionHeight = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting fillExtrusionHeight to a constant value expression should update fill-extrusion-height.");
+ XCTAssertEqualObjects(layer.fillExtrusionHeight, constantExpression,
+ @"fillExtrusionHeight should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.fillExtrusionHeight = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getFillExtrusionHeight(), propertyValue,
- @"Setting fillExtrusionHeight to a camera function should update fill-extrusion-height.");
- XCTAssertEqualObjects(layer.fillExtrusionHeight, functionStyleValue,
- @"fillExtrusionHeight should round-trip camera functions.");
+ @"Setting fillExtrusionHeight to a camera expression should update fill-extrusion-height.");
+ XCTAssertEqualObjects(layer.fillExtrusionHeight, functionExpression,
+ @"fillExtrusionHeight should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.fillExtrusionHeight = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.fillExtrusionHeight = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getFillExtrusionHeight(), propertyValue,
- @"Setting fillExtrusionHeight to a source function should update fill-extrusion-height.");
- XCTAssertEqualObjects(layer.fillExtrusionHeight, functionStyleValue,
- @"fillExtrusionHeight should round-trip source functions.");
+ @"Setting fillExtrusionHeight to a data expression should update fill-extrusion-height.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.fillExtrusionHeight, pedanticFunctionExpression,
+ @"fillExtrusionHeight should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.fillExtrusionHeight = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.fillExtrusionHeight = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -225,15 +242,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getFillExtrusionHeight(), propertyValue,
- @"Setting fillExtrusionHeight to a composite function should update fill-extrusion-height.");
- XCTAssertEqualObjects(layer.fillExtrusionHeight, functionStyleValue,
- @"fillExtrusionHeight should round-trip composite functions.");
+ @"Setting fillExtrusionHeight to a camera-data expression should update fill-extrusion-height.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.fillExtrusionHeight, pedanticFunctionExpression,
+ @"fillExtrusionHeight should round-trip camera-data expressions.");
layer.fillExtrusionHeight = nil;
XCTAssertTrue(rawLayer->getFillExtrusionHeight().isUndefined(),
@"Unsetting fillExtrusionHeight should return fill-extrusion-height to the default value.");
- XCTAssertEqualObjects(layer.fillExtrusionHeight, defaultStyleValue,
+ XCTAssertEqualObjects(layer.fillExtrusionHeight, defaultExpression,
@"fillExtrusionHeight should return the default value after being unset.");
// Transition property test
layer.fillExtrusionHeightTransition = transitionTest;
@@ -250,39 +268,44 @@
{
XCTAssertTrue(rawLayer->getFillExtrusionOpacity().isUndefined(),
@"fill-extrusion-opacity should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillExtrusionOpacity;
+ NSExpression *defaultExpression = layer.fillExtrusionOpacity;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.fillExtrusionOpacity = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.fillExtrusionOpacity = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getFillExtrusionOpacity(), propertyValue,
- @"Setting fillExtrusionOpacity to a constant value should update fill-extrusion-opacity.");
- XCTAssertEqualObjects(layer.fillExtrusionOpacity, constantStyleValue,
- @"fillExtrusionOpacity should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.fillExtrusionOpacity = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting fillExtrusionOpacity to a constant value expression should update fill-extrusion-opacity.");
+ XCTAssertEqualObjects(layer.fillExtrusionOpacity, constantExpression,
+ @"fillExtrusionOpacity should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.fillExtrusionOpacity = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getFillExtrusionOpacity(), propertyValue,
- @"Setting fillExtrusionOpacity to a camera function should update fill-extrusion-opacity.");
- XCTAssertEqualObjects(layer.fillExtrusionOpacity, functionStyleValue,
- @"fillExtrusionOpacity should round-trip camera functions.");
+ @"Setting fillExtrusionOpacity to a camera expression should update fill-extrusion-opacity.");
+ XCTAssertEqualObjects(layer.fillExtrusionOpacity, functionExpression,
+ @"fillExtrusionOpacity should round-trip camera expressions.");
layer.fillExtrusionOpacity = nil;
XCTAssertTrue(rawLayer->getFillExtrusionOpacity().isUndefined(),
@"Unsetting fillExtrusionOpacity should return fill-extrusion-opacity to the default value.");
- XCTAssertEqualObjects(layer.fillExtrusionOpacity, defaultStyleValue,
+ XCTAssertEqualObjects(layer.fillExtrusionOpacity, defaultExpression,
@"fillExtrusionOpacity should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.fillExtrusionOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.fillExtrusionOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.fillExtrusionOpacity = functionExpression, NSException, NSInvalidArgumentException, @"MGLFillExtrusionLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.fillExtrusionOpacity = functionExpression, NSException, NSInvalidArgumentException, @"MGLFillExtrusionLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
// Transition property test
layer.fillExtrusionOpacityTransition = transitionTest;
auto toptions = rawLayer->getFillExtrusionOpacityTransition();
@@ -298,39 +321,44 @@
{
XCTAssertTrue(rawLayer->getFillExtrusionPattern().isUndefined(),
@"fill-extrusion-pattern should be unset initially.");
- MGLStyleValue<NSString *> *defaultStyleValue = layer.fillExtrusionPattern;
+ NSExpression *defaultExpression = layer.fillExtrusionPattern;
- MGLStyleValue<NSString *> *constantStyleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Fill Extrusion Pattern"];
- layer.fillExtrusionPattern = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'Fill Extrusion Pattern'"];
+ layer.fillExtrusionPattern = constantExpression;
mbgl::style::PropertyValue<std::string> propertyValue = { "Fill Extrusion Pattern" };
XCTAssertEqual(rawLayer->getFillExtrusionPattern(), propertyValue,
- @"Setting fillExtrusionPattern to a constant value should update fill-extrusion-pattern.");
- XCTAssertEqualObjects(layer.fillExtrusionPattern, constantStyleValue,
- @"fillExtrusionPattern should round-trip constant values.");
-
- MGLStyleValue<NSString *> * functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.fillExtrusionPattern = functionStyleValue;
-
- mbgl::style::IntervalStops<std::string> intervalStops = { {{18, "Fill Extrusion Pattern"}} };
+ @"Setting fillExtrusionPattern to a constant value expression should update fill-extrusion-pattern.");
+ XCTAssertEqualObjects(layer.fillExtrusionPattern, constantExpression,
+ @"fillExtrusionPattern should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'Fill Extrusion Pattern'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.fillExtrusionPattern = functionExpression;
+
+ mbgl::style::IntervalStops<std::string> intervalStops = {{
+ { -INFINITY, "Fill Extrusion Pattern" },
+ { 18, "Fill Extrusion Pattern" },
+ }};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
XCTAssertEqual(rawLayer->getFillExtrusionPattern(), propertyValue,
- @"Setting fillExtrusionPattern to a camera function should update fill-extrusion-pattern.");
- XCTAssertEqualObjects(layer.fillExtrusionPattern, functionStyleValue,
- @"fillExtrusionPattern should round-trip camera functions.");
+ @"Setting fillExtrusionPattern to a camera expression should update fill-extrusion-pattern.");
+ XCTAssertEqualObjects(layer.fillExtrusionPattern, functionExpression,
+ @"fillExtrusionPattern should round-trip camera expressions.");
layer.fillExtrusionPattern = nil;
XCTAssertTrue(rawLayer->getFillExtrusionPattern().isUndefined(),
@"Unsetting fillExtrusionPattern should return fill-extrusion-pattern to the default value.");
- XCTAssertEqualObjects(layer.fillExtrusionPattern, defaultStyleValue,
+ XCTAssertEqualObjects(layer.fillExtrusionPattern, defaultExpression,
@"fillExtrusionPattern should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.fillExtrusionPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.fillExtrusionPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.fillExtrusionPattern = functionExpression, NSException, NSInvalidArgumentException, @"MGLFillExtrusionLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.fillExtrusionPattern = functionExpression, NSException, NSInvalidArgumentException, @"MGLFillExtrusionLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
// Transition property test
layer.fillExtrusionPatternTransition = transitionTest;
auto toptions = rawLayer->getFillExtrusionPatternTransition();
@@ -346,84 +374,94 @@
{
XCTAssertTrue(rawLayer->getFillExtrusionTranslate().isUndefined(),
@"fill-extrusion-translate should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.fillExtrusionTranslation;
+ NSExpression *defaultExpression = layer.fillExtrusionTranslation;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@",
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
- layer.fillExtrusionTranslation = constantStyleValue;
+ layer.fillExtrusionTranslation = constantExpression;
mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getFillExtrusionTranslate(), propertyValue,
- @"Setting fillExtrusionTranslation to a constant value should update fill-extrusion-translate.");
- XCTAssertEqualObjects(layer.fillExtrusionTranslation, constantStyleValue,
- @"fillExtrusionTranslation should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.fillExtrusionTranslation = functionStyleValue;
-
- mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} };
+ @"Setting fillExtrusionTranslation to a constant value expression should update fill-extrusion-translate.");
+ XCTAssertEqualObjects(layer.fillExtrusionTranslation, constantExpression,
+ @"fillExtrusionTranslation should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"{1, 1}"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.fillExtrusionTranslation = functionExpression;
+
+ mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = {{
+ { -INFINITY, { 1, 1 } },
+ { 18, { 1, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
XCTAssertEqual(rawLayer->getFillExtrusionTranslate(), propertyValue,
- @"Setting fillExtrusionTranslation to a camera function should update fill-extrusion-translate.");
- XCTAssertEqualObjects(layer.fillExtrusionTranslation, functionStyleValue,
- @"fillExtrusionTranslation should round-trip camera functions.");
+ @"Setting fillExtrusionTranslation to a camera expression should update fill-extrusion-translate.");
+ XCTAssertEqualObjects(layer.fillExtrusionTranslation, functionExpression,
+ @"fillExtrusionTranslation should round-trip camera expressions.");
layer.fillExtrusionTranslation = nil;
XCTAssertTrue(rawLayer->getFillExtrusionTranslate().isUndefined(),
@"Unsetting fillExtrusionTranslation should return fill-extrusion-translate to the default value.");
- XCTAssertEqualObjects(layer.fillExtrusionTranslation, defaultStyleValue,
+ XCTAssertEqualObjects(layer.fillExtrusionTranslation, defaultExpression,
@"fillExtrusionTranslation should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.fillExtrusionTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.fillExtrusionTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.fillExtrusionTranslation = functionExpression, NSException, NSInvalidArgumentException, @"MGLFillExtrusionLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.fillExtrusionTranslation = functionExpression, NSException, NSInvalidArgumentException, @"MGLFillExtrusionLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// fill-extrusion-translate-anchor
{
XCTAssertTrue(rawLayer->getFillExtrusionTranslateAnchor().isUndefined(),
@"fill-extrusion-translate-anchor should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.fillExtrusionTranslationAnchor;
+ NSExpression *defaultExpression = layer.fillExtrusionTranslationAnchor;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLFillExtrusionTranslationAnchor:MGLFillExtrusionTranslationAnchorViewport]];
- layer.fillExtrusionTranslationAnchor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ layer.fillExtrusionTranslationAnchor = constantExpression;
mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
XCTAssertEqual(rawLayer->getFillExtrusionTranslateAnchor(), propertyValue,
- @"Setting fillExtrusionTranslationAnchor to a constant value should update fill-extrusion-translate-anchor.");
- XCTAssertEqualObjects(layer.fillExtrusionTranslationAnchor, constantStyleValue,
- @"fillExtrusionTranslationAnchor should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.fillExtrusionTranslationAnchor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} };
+ @"Setting fillExtrusionTranslationAnchor to a constant value expression should update fill-extrusion-translate-anchor.");
+ XCTAssertEqualObjects(layer.fillExtrusionTranslationAnchor, constantExpression,
+ @"fillExtrusionTranslationAnchor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.fillExtrusionTranslationAnchor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = {{
+ { -INFINITY, mbgl::style::TranslateAnchorType::Viewport },
+ { 18, mbgl::style::TranslateAnchorType::Viewport },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
XCTAssertEqual(rawLayer->getFillExtrusionTranslateAnchor(), propertyValue,
- @"Setting fillExtrusionTranslationAnchor to a camera function should update fill-extrusion-translate-anchor.");
- XCTAssertEqualObjects(layer.fillExtrusionTranslationAnchor, functionStyleValue,
- @"fillExtrusionTranslationAnchor should round-trip camera functions.");
+ @"Setting fillExtrusionTranslationAnchor to a camera expression should update fill-extrusion-translate-anchor.");
+ XCTAssertEqualObjects(layer.fillExtrusionTranslationAnchor, functionExpression,
+ @"fillExtrusionTranslationAnchor should round-trip camera expressions.");
layer.fillExtrusionTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getFillExtrusionTranslateAnchor().isUndefined(),
@"Unsetting fillExtrusionTranslationAnchor should return fill-extrusion-translate-anchor to the default value.");
- XCTAssertEqualObjects(layer.fillExtrusionTranslationAnchor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.fillExtrusionTranslationAnchor, defaultExpression,
@"fillExtrusionTranslationAnchor should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.fillExtrusionTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.fillExtrusionTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.fillExtrusionTranslationAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLFillExtrusionLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.fillExtrusionTranslationAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLFillExtrusionLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
}
diff --git a/platform/darwin/test/MGLFillStyleLayerTests.mm b/platform/darwin/test/MGLFillStyleLayerTests.mm
index 85f0b24fa7..a5019f1032 100644
--- a/platform/darwin/test/MGLFillStyleLayerTests.mm
+++ b/platform/darwin/test/MGLFillStyleLayerTests.mm
@@ -30,8 +30,8 @@
XCTAssertNil(layer.sourceLayerIdentifier);
XCTAssertNil(layer.predicate);
- layer.predicate = [NSPredicate predicateWithValue:NO];
- XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
+ layer.predicate = [NSPredicate predicateWithFormat:@"$featureIdentifier = 1"];
+ XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithFormat:@"$featureIdentifier = 1"]);
layer.predicate = nil;
XCTAssertNil(layer.predicate);
}
@@ -52,79 +52,89 @@
{
XCTAssertTrue(rawLayer->getFillAntialias().isUndefined(),
@"fill-antialias should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillAntialiased;
+ NSExpression *defaultExpression = layer.fillAntialiased;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@NO];
- layer.fillAntialiased = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"false"];
+ layer.fillAntialiased = constantExpression;
mbgl::style::PropertyValue<bool> propertyValue = { false };
XCTAssertEqual(rawLayer->getFillAntialias(), propertyValue,
- @"Setting fillAntialiased to a constant value should update fill-antialias.");
- XCTAssertEqualObjects(layer.fillAntialiased, constantStyleValue,
- @"fillAntialiased should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.fillAntialiased = functionStyleValue;
-
- mbgl::style::IntervalStops<bool> intervalStops = { {{18, false}} };
+ @"Setting fillAntialiased to a constant value expression should update fill-antialias.");
+ XCTAssertEqualObjects(layer.fillAntialiased, constantExpression,
+ @"fillAntialiased should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"false"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.fillAntialiased = functionExpression;
+
+ mbgl::style::IntervalStops<bool> intervalStops = {{
+ { -INFINITY, false },
+ { 18, false },
+ }};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
XCTAssertEqual(rawLayer->getFillAntialias(), propertyValue,
- @"Setting fillAntialiased to a camera function should update fill-antialias.");
- XCTAssertEqualObjects(layer.fillAntialiased, functionStyleValue,
- @"fillAntialiased should round-trip camera functions.");
+ @"Setting fillAntialiased to a camera expression should update fill-antialias.");
+ XCTAssertEqualObjects(layer.fillAntialiased, functionExpression,
+ @"fillAntialiased should round-trip camera expressions.");
layer.fillAntialiased = nil;
XCTAssertTrue(rawLayer->getFillAntialias().isUndefined(),
@"Unsetting fillAntialiased should return fill-antialias to the default value.");
- XCTAssertEqualObjects(layer.fillAntialiased, defaultStyleValue,
+ XCTAssertEqualObjects(layer.fillAntialiased, defaultExpression,
@"fillAntialiased should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.fillAntialiased = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.fillAntialiased = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.fillAntialiased = functionExpression, NSException, NSInvalidArgumentException, @"MGLFillLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.fillAntialiased = functionExpression, NSException, NSInvalidArgumentException, @"MGLFillLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// fill-color
{
XCTAssertTrue(rawLayer->getFillColor().isUndefined(),
@"fill-color should be unset initially.");
- MGLStyleValue<MGLColor *> *defaultStyleValue = layer.fillColor;
+ NSExpression *defaultExpression = layer.fillColor;
- MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.fillColor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ layer.fillColor = constantExpression;
mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getFillColor(), propertyValue,
- @"Setting fillColor to a constant value should update fill-color.");
- XCTAssertEqualObjects(layer.fillColor, constantStyleValue,
- @"fillColor should round-trip constant values.");
-
- MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.fillColor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ @"Setting fillColor to a constant value expression should update fill-color.");
+ XCTAssertEqualObjects(layer.fillColor, constantExpression,
+ @"fillColor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.fillColor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = {{
+ { -INFINITY, { 1, 0, 0, 1 } },
+ { 18, { 1, 0, 0, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
XCTAssertEqual(rawLayer->getFillColor(), propertyValue,
- @"Setting fillColor to a camera function should update fill-color.");
- XCTAssertEqualObjects(layer.fillColor, functionStyleValue,
- @"fillColor should round-trip camera functions.");
+ @"Setting fillColor to a camera expression should update fill-color.");
+ XCTAssertEqualObjects(layer.fillColor, functionExpression,
+ @"fillColor should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.fillColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.fillColor = functionExpression;
mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getFillColor(), propertyValue,
- @"Setting fillColor to a source function should update fill-color.");
- XCTAssertEqualObjects(layer.fillColor, functionStyleValue,
- @"fillColor should round-trip source functions.");
+ @"Setting fillColor to a data expression should update fill-color.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.fillColor, pedanticFunctionExpression,
+ @"fillColor should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.fillColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.fillColor = functionExpression;
std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -132,15 +142,16 @@
propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getFillColor(), propertyValue,
- @"Setting fillColor to a composite function should update fill-color.");
- XCTAssertEqualObjects(layer.fillColor, functionStyleValue,
- @"fillColor should round-trip composite functions.");
+ @"Setting fillColor to a camera-data expression should update fill-color.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.fillColor, pedanticFunctionExpression,
+ @"fillColor should round-trip camera-data expressions.");
layer.fillColor = nil;
XCTAssertTrue(rawLayer->getFillColor().isUndefined(),
@"Unsetting fillColor should return fill-color to the default value.");
- XCTAssertEqualObjects(layer.fillColor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.fillColor, defaultExpression,
@"fillColor should return the default value after being unset.");
// Transition property test
layer.fillColorTransition = transitionTest;
@@ -157,40 +168,45 @@
{
XCTAssertTrue(rawLayer->getFillOpacity().isUndefined(),
@"fill-opacity should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillOpacity;
+ NSExpression *defaultExpression = layer.fillOpacity;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.fillOpacity = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.fillOpacity = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue,
- @"Setting fillOpacity to a constant value should update fill-opacity.");
- XCTAssertEqualObjects(layer.fillOpacity, constantStyleValue,
- @"fillOpacity should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.fillOpacity = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting fillOpacity to a constant value expression should update fill-opacity.");
+ XCTAssertEqualObjects(layer.fillOpacity, constantExpression,
+ @"fillOpacity should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.fillOpacity = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue,
- @"Setting fillOpacity to a camera function should update fill-opacity.");
- XCTAssertEqualObjects(layer.fillOpacity, functionStyleValue,
- @"fillOpacity should round-trip camera functions.");
+ @"Setting fillOpacity to a camera expression should update fill-opacity.");
+ XCTAssertEqualObjects(layer.fillOpacity, functionExpression,
+ @"fillOpacity should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.fillOpacity = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.fillOpacity = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue,
- @"Setting fillOpacity to a source function should update fill-opacity.");
- XCTAssertEqualObjects(layer.fillOpacity, functionStyleValue,
- @"fillOpacity should round-trip source functions.");
+ @"Setting fillOpacity to a data expression should update fill-opacity.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.fillOpacity, pedanticFunctionExpression,
+ @"fillOpacity should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.fillOpacity = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.fillOpacity = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -198,15 +214,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue,
- @"Setting fillOpacity to a composite function should update fill-opacity.");
- XCTAssertEqualObjects(layer.fillOpacity, functionStyleValue,
- @"fillOpacity should round-trip composite functions.");
+ @"Setting fillOpacity to a camera-data expression should update fill-opacity.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.fillOpacity, pedanticFunctionExpression,
+ @"fillOpacity should round-trip camera-data expressions.");
layer.fillOpacity = nil;
XCTAssertTrue(rawLayer->getFillOpacity().isUndefined(),
@"Unsetting fillOpacity should return fill-opacity to the default value.");
- XCTAssertEqualObjects(layer.fillOpacity, defaultStyleValue,
+ XCTAssertEqualObjects(layer.fillOpacity, defaultExpression,
@"fillOpacity should return the default value after being unset.");
// Transition property test
layer.fillOpacityTransition = transitionTest;
@@ -223,40 +240,45 @@
{
XCTAssertTrue(rawLayer->getFillOutlineColor().isUndefined(),
@"fill-outline-color should be unset initially.");
- MGLStyleValue<MGLColor *> *defaultStyleValue = layer.fillOutlineColor;
+ NSExpression *defaultExpression = layer.fillOutlineColor;
- MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.fillOutlineColor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ layer.fillOutlineColor = constantExpression;
mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue,
- @"Setting fillOutlineColor to a constant value should update fill-outline-color.");
- XCTAssertEqualObjects(layer.fillOutlineColor, constantStyleValue,
- @"fillOutlineColor should round-trip constant values.");
-
- MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.fillOutlineColor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ @"Setting fillOutlineColor to a constant value expression should update fill-outline-color.");
+ XCTAssertEqualObjects(layer.fillOutlineColor, constantExpression,
+ @"fillOutlineColor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.fillOutlineColor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = {{
+ { -INFINITY, { 1, 0, 0, 1 } },
+ { 18, { 1, 0, 0, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue,
- @"Setting fillOutlineColor to a camera function should update fill-outline-color.");
- XCTAssertEqualObjects(layer.fillOutlineColor, functionStyleValue,
- @"fillOutlineColor should round-trip camera functions.");
+ @"Setting fillOutlineColor to a camera expression should update fill-outline-color.");
+ XCTAssertEqualObjects(layer.fillOutlineColor, functionExpression,
+ @"fillOutlineColor should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.fillOutlineColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.fillOutlineColor = functionExpression;
mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue,
- @"Setting fillOutlineColor to a source function should update fill-outline-color.");
- XCTAssertEqualObjects(layer.fillOutlineColor, functionStyleValue,
- @"fillOutlineColor should round-trip source functions.");
+ @"Setting fillOutlineColor to a data expression should update fill-outline-color.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.fillOutlineColor, pedanticFunctionExpression,
+ @"fillOutlineColor should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.fillOutlineColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.fillOutlineColor = functionExpression;
std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -264,15 +286,16 @@
propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue,
- @"Setting fillOutlineColor to a composite function should update fill-outline-color.");
- XCTAssertEqualObjects(layer.fillOutlineColor, functionStyleValue,
- @"fillOutlineColor should round-trip composite functions.");
+ @"Setting fillOutlineColor to a camera-data expression should update fill-outline-color.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.fillOutlineColor, pedanticFunctionExpression,
+ @"fillOutlineColor should round-trip camera-data expressions.");
layer.fillOutlineColor = nil;
XCTAssertTrue(rawLayer->getFillOutlineColor().isUndefined(),
@"Unsetting fillOutlineColor should return fill-outline-color to the default value.");
- XCTAssertEqualObjects(layer.fillOutlineColor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.fillOutlineColor, defaultExpression,
@"fillOutlineColor should return the default value after being unset.");
// Transition property test
layer.fillOutlineColorTransition = transitionTest;
@@ -289,39 +312,44 @@
{
XCTAssertTrue(rawLayer->getFillPattern().isUndefined(),
@"fill-pattern should be unset initially.");
- MGLStyleValue<NSString *> *defaultStyleValue = layer.fillPattern;
+ NSExpression *defaultExpression = layer.fillPattern;
- MGLStyleValue<NSString *> *constantStyleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Fill Pattern"];
- layer.fillPattern = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'Fill Pattern'"];
+ layer.fillPattern = constantExpression;
mbgl::style::PropertyValue<std::string> propertyValue = { "Fill Pattern" };
XCTAssertEqual(rawLayer->getFillPattern(), propertyValue,
- @"Setting fillPattern to a constant value should update fill-pattern.");
- XCTAssertEqualObjects(layer.fillPattern, constantStyleValue,
- @"fillPattern should round-trip constant values.");
-
- MGLStyleValue<NSString *> * functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.fillPattern = functionStyleValue;
-
- mbgl::style::IntervalStops<std::string> intervalStops = { {{18, "Fill Pattern"}} };
+ @"Setting fillPattern to a constant value expression should update fill-pattern.");
+ XCTAssertEqualObjects(layer.fillPattern, constantExpression,
+ @"fillPattern should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'Fill Pattern'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.fillPattern = functionExpression;
+
+ mbgl::style::IntervalStops<std::string> intervalStops = {{
+ { -INFINITY, "Fill Pattern" },
+ { 18, "Fill Pattern" },
+ }};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
XCTAssertEqual(rawLayer->getFillPattern(), propertyValue,
- @"Setting fillPattern to a camera function should update fill-pattern.");
- XCTAssertEqualObjects(layer.fillPattern, functionStyleValue,
- @"fillPattern should round-trip camera functions.");
+ @"Setting fillPattern to a camera expression should update fill-pattern.");
+ XCTAssertEqualObjects(layer.fillPattern, functionExpression,
+ @"fillPattern should round-trip camera expressions.");
layer.fillPattern = nil;
XCTAssertTrue(rawLayer->getFillPattern().isUndefined(),
@"Unsetting fillPattern should return fill-pattern to the default value.");
- XCTAssertEqualObjects(layer.fillPattern, defaultStyleValue,
+ XCTAssertEqualObjects(layer.fillPattern, defaultExpression,
@"fillPattern should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.fillPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.fillPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.fillPattern = functionExpression, NSException, NSInvalidArgumentException, @"MGLFillLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.fillPattern = functionExpression, NSException, NSInvalidArgumentException, @"MGLFillLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
// Transition property test
layer.fillPatternTransition = transitionTest;
auto toptions = rawLayer->getFillPatternTransition();
@@ -337,84 +365,94 @@
{
XCTAssertTrue(rawLayer->getFillTranslate().isUndefined(),
@"fill-translate should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.fillTranslation;
+ NSExpression *defaultExpression = layer.fillTranslation;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@",
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
- layer.fillTranslation = constantStyleValue;
+ layer.fillTranslation = constantExpression;
mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getFillTranslate(), propertyValue,
- @"Setting fillTranslation to a constant value should update fill-translate.");
- XCTAssertEqualObjects(layer.fillTranslation, constantStyleValue,
- @"fillTranslation should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.fillTranslation = functionStyleValue;
-
- mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} };
+ @"Setting fillTranslation to a constant value expression should update fill-translate.");
+ XCTAssertEqualObjects(layer.fillTranslation, constantExpression,
+ @"fillTranslation should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"{1, 1}"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.fillTranslation = functionExpression;
+
+ mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = {{
+ { -INFINITY, { 1, 1 } },
+ { 18, { 1, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
XCTAssertEqual(rawLayer->getFillTranslate(), propertyValue,
- @"Setting fillTranslation to a camera function should update fill-translate.");
- XCTAssertEqualObjects(layer.fillTranslation, functionStyleValue,
- @"fillTranslation should round-trip camera functions.");
+ @"Setting fillTranslation to a camera expression should update fill-translate.");
+ XCTAssertEqualObjects(layer.fillTranslation, functionExpression,
+ @"fillTranslation should round-trip camera expressions.");
layer.fillTranslation = nil;
XCTAssertTrue(rawLayer->getFillTranslate().isUndefined(),
@"Unsetting fillTranslation should return fill-translate to the default value.");
- XCTAssertEqualObjects(layer.fillTranslation, defaultStyleValue,
+ XCTAssertEqualObjects(layer.fillTranslation, defaultExpression,
@"fillTranslation should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.fillTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.fillTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.fillTranslation = functionExpression, NSException, NSInvalidArgumentException, @"MGLFillLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.fillTranslation = functionExpression, NSException, NSInvalidArgumentException, @"MGLFillLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// fill-translate-anchor
{
XCTAssertTrue(rawLayer->getFillTranslateAnchor().isUndefined(),
@"fill-translate-anchor should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.fillTranslationAnchor;
+ NSExpression *defaultExpression = layer.fillTranslationAnchor;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLFillTranslationAnchor:MGLFillTranslationAnchorViewport]];
- layer.fillTranslationAnchor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ layer.fillTranslationAnchor = constantExpression;
mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
XCTAssertEqual(rawLayer->getFillTranslateAnchor(), propertyValue,
- @"Setting fillTranslationAnchor to a constant value should update fill-translate-anchor.");
- XCTAssertEqualObjects(layer.fillTranslationAnchor, constantStyleValue,
- @"fillTranslationAnchor should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.fillTranslationAnchor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} };
+ @"Setting fillTranslationAnchor to a constant value expression should update fill-translate-anchor.");
+ XCTAssertEqualObjects(layer.fillTranslationAnchor, constantExpression,
+ @"fillTranslationAnchor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.fillTranslationAnchor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = {{
+ { -INFINITY, mbgl::style::TranslateAnchorType::Viewport },
+ { 18, mbgl::style::TranslateAnchorType::Viewport },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
XCTAssertEqual(rawLayer->getFillTranslateAnchor(), propertyValue,
- @"Setting fillTranslationAnchor to a camera function should update fill-translate-anchor.");
- XCTAssertEqualObjects(layer.fillTranslationAnchor, functionStyleValue,
- @"fillTranslationAnchor should round-trip camera functions.");
+ @"Setting fillTranslationAnchor to a camera expression should update fill-translate-anchor.");
+ XCTAssertEqualObjects(layer.fillTranslationAnchor, functionExpression,
+ @"fillTranslationAnchor should round-trip camera expressions.");
layer.fillTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getFillTranslateAnchor().isUndefined(),
@"Unsetting fillTranslationAnchor should return fill-translate-anchor to the default value.");
- XCTAssertEqualObjects(layer.fillTranslationAnchor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.fillTranslationAnchor, defaultExpression,
@"fillTranslationAnchor should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.fillTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.fillTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.fillTranslationAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLFillLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.fillTranslationAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLFillLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
}
diff --git a/platform/darwin/test/MGLGeometryTests.mm b/platform/darwin/test/MGLGeometryTests.mm
index 1c85470188..a0ddecf77e 100644
--- a/platform/darwin/test/MGLGeometryTests.mm
+++ b/platform/darwin/test/MGLGeometryTests.mm
@@ -163,4 +163,13 @@
[NSValue valueWithMGLCoordinate:quad.bottomRight],
@"Quad bottom right should be computed correctly.");
}
+
+- (void)testMGLMapPoint {
+ MGLMapPoint point = MGLMapPointForCoordinate(CLLocationCoordinate2DMake(37.936, -80.425), 0.0);
+
+ MGLMapPoint roundTrippedPoint = [NSValue valueWithMGLMapPoint:point].MGLMapPointValue;
+ XCTAssertEqual(point.x, roundTrippedPoint.x);
+ XCTAssertEqual(point.y, roundTrippedPoint.y);
+ XCTAssertEqual(point.zoomLevel, roundTrippedPoint.zoomLevel);
+}
@end
diff --git a/platform/darwin/test/MGLHeatmapColorTests.mm b/platform/darwin/test/MGLHeatmapColorTests.mm
new file mode 100644
index 0000000000..bed777ae05
--- /dev/null
+++ b/platform/darwin/test/MGLHeatmapColorTests.mm
@@ -0,0 +1,62 @@
+#import <Mapbox/Mapbox.h>
+#import <XCTest/XCTest.h>
+
+#import "MGLStyleLayer_Private.h"
+
+#include <mbgl/style/layers/heatmap_layer.hpp>
+
+@interface MGLHeatmapColorTests : XCTestCase <MGLMapViewDelegate>
+@end
+
+@implementation MGLHeatmapColorTests
+
+- (void)testProperties {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+ MGLHeatmapStyleLayer *layer = [[MGLHeatmapStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+
+ auto rawLayer = layer.rawLayer->as<mbgl::style::HeatmapLayer>();
+
+ XCTAssertTrue(rawLayer->getHeatmapColor().isUndefined(),
+ @"heatmap-color should be unset initially.");
+ NSExpression *defaultExpression = layer.heatmapColor;
+
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ layer.heatmapColor = constantExpression;
+
+
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getHeatmapColor().evaluate(0.0), mbgl::Color::red(),
+ @"Setting heatmapColor to a constant value expression should update heatmap-color.");
+ XCTAssertEqualObjects(layer.heatmapColor, constantExpression,
+ @"heatmapColor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ NSExpression *constantExpression2 = [NSExpression expressionWithFormat:@"%@", [MGLColor blueColor]];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($heatmapDensity, %@, %@)", constantExpression, @{@12: constantExpression2}];
+ layer.heatmapColor = functionExpression;
+
+ XCTAssertEqual(rawLayer->getHeatmapColor().evaluate(11.0), mbgl::Color::red(),
+ @"Setting heatmapColor to an expression depending on $heatmapDensity should update heatmap-color.");
+ XCTAssertEqual(rawLayer->getHeatmapColor().evaluate(12.0), mbgl::Color::blue(),
+ @"Setting heatmapColor to an expression depending on $heatmapDensity should update heatmap-color.");
+ XCTAssertEqualObjects(layer.heatmapColor, functionExpression,
+ @"heatmapColor should round-trip expressions depending on $heatmapDensity.");
+
+ layer.heatmapColor = nil;
+ XCTAssertTrue(rawLayer->getHeatmapColor().isUndefined(),
+ @"Unsetting heatmapColor should return heatmap-color to the default value.");
+ // The contained colors aren’t object equal, even though their descriptions are.
+ XCTAssertEqualObjects(layer.heatmapColor.description, defaultExpression.description,
+ @"heatmapColor should return the default value after being unset.");
+
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ XCTAssertThrowsSpecificNamed(layer.heatmapColor = functionExpression, NSException, NSInvalidArgumentException, @"MGLHeatmapLayer should raise an exception if a camera expression is applied to heatmapColor.");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.heatmapColor = functionExpression, NSException, NSInvalidArgumentException, @"MGLHeatmapLayer should raise an exception if a data expression is applied to heatmapColor.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.heatmapColor = functionExpression, NSException, NSInvalidArgumentException, @"MGLHeatmapLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+}
+
+@end
diff --git a/platform/darwin/test/MGLHeatmapStyleLayerTests.mm b/platform/darwin/test/MGLHeatmapStyleLayerTests.mm
new file mode 100644
index 0000000000..e4b1917257
--- /dev/null
+++ b/platform/darwin/test/MGLHeatmapStyleLayerTests.mm
@@ -0,0 +1,300 @@
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
+
+#import "MGLStyleLayerTests.h"
+#import "../../darwin/src/NSDate+MGLAdditions.h"
+
+#import "MGLStyleLayer_Private.h"
+
+#include <mbgl/style/layers/heatmap_layer.hpp>
+#include <mbgl/style/transition_options.hpp>
+
+@interface MGLHeatmapLayerTests : MGLStyleLayerTests
+@end
+
+@implementation MGLHeatmapLayerTests
+
++ (NSString *)layerType {
+ return @"heatmap";
+}
+
+- (void)testPredicates {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+ MGLHeatmapStyleLayer *layer = [[MGLHeatmapStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+
+ XCTAssertNil(layer.sourceLayerIdentifier);
+ layer.sourceLayerIdentifier = @"layerID";
+ XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID");
+ layer.sourceLayerIdentifier = nil;
+ XCTAssertNil(layer.sourceLayerIdentifier);
+
+ XCTAssertNil(layer.predicate);
+ layer.predicate = [NSPredicate predicateWithFormat:@"$featureIdentifier = 1"];
+ XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithFormat:@"$featureIdentifier = 1"]);
+ layer.predicate = nil;
+ XCTAssertNil(layer.predicate);
+}
+
+- (void)testProperties {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+
+ MGLHeatmapStyleLayer *layer = [[MGLHeatmapStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+ XCTAssertNotEqual(layer.rawLayer, nullptr);
+ XCTAssertTrue(layer.rawLayer->is<mbgl::style::HeatmapLayer>());
+ auto rawLayer = layer.rawLayer->as<mbgl::style::HeatmapLayer>();
+
+ MGLTransition transitionTest = MGLTransitionMake(5, 4);
+
+
+ // heatmap-intensity
+ {
+ XCTAssertTrue(rawLayer->getHeatmapIntensity().isUndefined(),
+ @"heatmap-intensity should be unset initially.");
+ NSExpression *defaultExpression = layer.heatmapIntensity;
+
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.heatmapIntensity = constantExpression;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getHeatmapIntensity(), propertyValue,
+ @"Setting heatmapIntensity to a constant value expression should update heatmap-intensity.");
+ XCTAssertEqualObjects(layer.heatmapIntensity, constantExpression,
+ @"heatmapIntensity should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.heatmapIntensity = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getHeatmapIntensity(), propertyValue,
+ @"Setting heatmapIntensity to a camera expression should update heatmap-intensity.");
+ XCTAssertEqualObjects(layer.heatmapIntensity, functionExpression,
+ @"heatmapIntensity should round-trip camera expressions.");
+
+
+
+ layer.heatmapIntensity = nil;
+ XCTAssertTrue(rawLayer->getHeatmapIntensity().isUndefined(),
+ @"Unsetting heatmapIntensity should return heatmap-intensity to the default value.");
+ XCTAssertEqualObjects(layer.heatmapIntensity, defaultExpression,
+ @"heatmapIntensity should return the default value after being unset.");
+
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.heatmapIntensity = functionExpression, NSException, NSInvalidArgumentException, @"MGLHeatmapLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.heatmapIntensity = functionExpression, NSException, NSInvalidArgumentException, @"MGLHeatmapLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ // Transition property test
+ layer.heatmapIntensityTransition = transitionTest;
+ auto toptions = rawLayer->getHeatmapIntensityTransition();
+ XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay);
+ XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration);
+
+ MGLTransition heatmapIntensityTransition = layer.heatmapIntensityTransition;
+ XCTAssertEqual(heatmapIntensityTransition.delay, transitionTest.delay);
+ XCTAssertEqual(heatmapIntensityTransition.duration, transitionTest.duration);
+ }
+
+ // heatmap-opacity
+ {
+ XCTAssertTrue(rawLayer->getHeatmapOpacity().isUndefined(),
+ @"heatmap-opacity should be unset initially.");
+ NSExpression *defaultExpression = layer.heatmapOpacity;
+
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.heatmapOpacity = constantExpression;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getHeatmapOpacity(), propertyValue,
+ @"Setting heatmapOpacity to a constant value expression should update heatmap-opacity.");
+ XCTAssertEqualObjects(layer.heatmapOpacity, constantExpression,
+ @"heatmapOpacity should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.heatmapOpacity = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getHeatmapOpacity(), propertyValue,
+ @"Setting heatmapOpacity to a camera expression should update heatmap-opacity.");
+ XCTAssertEqualObjects(layer.heatmapOpacity, functionExpression,
+ @"heatmapOpacity should round-trip camera expressions.");
+
+
+
+ layer.heatmapOpacity = nil;
+ XCTAssertTrue(rawLayer->getHeatmapOpacity().isUndefined(),
+ @"Unsetting heatmapOpacity should return heatmap-opacity to the default value.");
+ XCTAssertEqualObjects(layer.heatmapOpacity, defaultExpression,
+ @"heatmapOpacity should return the default value after being unset.");
+
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.heatmapOpacity = functionExpression, NSException, NSInvalidArgumentException, @"MGLHeatmapLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.heatmapOpacity = functionExpression, NSException, NSInvalidArgumentException, @"MGLHeatmapLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ // Transition property test
+ layer.heatmapOpacityTransition = transitionTest;
+ auto toptions = rawLayer->getHeatmapOpacityTransition();
+ XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay);
+ XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration);
+
+ MGLTransition heatmapOpacityTransition = layer.heatmapOpacityTransition;
+ XCTAssertEqual(heatmapOpacityTransition.delay, transitionTest.delay);
+ XCTAssertEqual(heatmapOpacityTransition.duration, transitionTest.duration);
+ }
+
+ // heatmap-radius
+ {
+ XCTAssertTrue(rawLayer->getHeatmapRadius().isUndefined(),
+ @"heatmap-radius should be unset initially.");
+ NSExpression *defaultExpression = layer.heatmapRadius;
+
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.heatmapRadius = constantExpression;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getHeatmapRadius(), propertyValue,
+ @"Setting heatmapRadius to a constant value expression should update heatmap-radius.");
+ XCTAssertEqualObjects(layer.heatmapRadius, constantExpression,
+ @"heatmapRadius should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.heatmapRadius = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getHeatmapRadius(), propertyValue,
+ @"Setting heatmapRadius to a camera expression should update heatmap-radius.");
+ XCTAssertEqualObjects(layer.heatmapRadius, functionExpression,
+ @"heatmapRadius should round-trip camera expressions.");
+
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.heatmapRadius = functionExpression;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getHeatmapRadius(), propertyValue,
+ @"Setting heatmapRadius to a data expression should update heatmap-radius.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.heatmapRadius, pedanticFunctionExpression,
+ @"heatmapRadius should round-trip data expressions.");
+
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.heatmapRadius = functionExpression;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getHeatmapRadius(), propertyValue,
+ @"Setting heatmapRadius to a camera-data expression should update heatmap-radius.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.heatmapRadius, pedanticFunctionExpression,
+ @"heatmapRadius should round-trip camera-data expressions.");
+
+
+ layer.heatmapRadius = nil;
+ XCTAssertTrue(rawLayer->getHeatmapRadius().isUndefined(),
+ @"Unsetting heatmapRadius should return heatmap-radius to the default value.");
+ XCTAssertEqualObjects(layer.heatmapRadius, defaultExpression,
+ @"heatmapRadius should return the default value after being unset.");
+ // Transition property test
+ layer.heatmapRadiusTransition = transitionTest;
+ auto toptions = rawLayer->getHeatmapRadiusTransition();
+ XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay);
+ XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration);
+
+ MGLTransition heatmapRadiusTransition = layer.heatmapRadiusTransition;
+ XCTAssertEqual(heatmapRadiusTransition.delay, transitionTest.delay);
+ XCTAssertEqual(heatmapRadiusTransition.duration, transitionTest.duration);
+ }
+
+ // heatmap-weight
+ {
+ XCTAssertTrue(rawLayer->getHeatmapWeight().isUndefined(),
+ @"heatmap-weight should be unset initially.");
+ NSExpression *defaultExpression = layer.heatmapWeight;
+
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.heatmapWeight = constantExpression;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getHeatmapWeight(), propertyValue,
+ @"Setting heatmapWeight to a constant value expression should update heatmap-weight.");
+ XCTAssertEqualObjects(layer.heatmapWeight, constantExpression,
+ @"heatmapWeight should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.heatmapWeight = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getHeatmapWeight(), propertyValue,
+ @"Setting heatmapWeight to a camera expression should update heatmap-weight.");
+ XCTAssertEqualObjects(layer.heatmapWeight, functionExpression,
+ @"heatmapWeight should round-trip camera expressions.");
+
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.heatmapWeight = functionExpression;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getHeatmapWeight(), propertyValue,
+ @"Setting heatmapWeight to a data expression should update heatmap-weight.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.heatmapWeight, pedanticFunctionExpression,
+ @"heatmapWeight should round-trip data expressions.");
+
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.heatmapWeight = functionExpression;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getHeatmapWeight(), propertyValue,
+ @"Setting heatmapWeight to a camera-data expression should update heatmap-weight.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.heatmapWeight, pedanticFunctionExpression,
+ @"heatmapWeight should round-trip camera-data expressions.");
+
+
+ layer.heatmapWeight = nil;
+ XCTAssertTrue(rawLayer->getHeatmapWeight().isUndefined(),
+ @"Unsetting heatmapWeight should return heatmap-weight to the default value.");
+ XCTAssertEqualObjects(layer.heatmapWeight, defaultExpression,
+ @"heatmapWeight should return the default value after being unset.");
+ }
+}
+
+- (void)testPropertyNames {
+ [self testPropertyName:@"heatmap-intensity" isBoolean:NO];
+ [self testPropertyName:@"heatmap-opacity" isBoolean:NO];
+ [self testPropertyName:@"heatmap-radius" isBoolean:NO];
+ [self testPropertyName:@"heatmap-weight" isBoolean:NO];
+}
+
+@end
diff --git a/platform/darwin/test/MGLHillshadeStyleLayerTests.mm b/platform/darwin/test/MGLHillshadeStyleLayerTests.mm
new file mode 100644
index 0000000000..34937d1674
--- /dev/null
+++ b/platform/darwin/test/MGLHillshadeStyleLayerTests.mm
@@ -0,0 +1,348 @@
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
+
+#import "MGLStyleLayerTests.h"
+#import "../../darwin/src/NSDate+MGLAdditions.h"
+
+#import "MGLStyleLayer_Private.h"
+
+#include <mbgl/style/layers/hillshade_layer.hpp>
+#include <mbgl/style/transition_options.hpp>
+
+@interface MGLHillshadeLayerTests : MGLStyleLayerTests
+@end
+
+@implementation MGLHillshadeLayerTests
+
++ (NSString *)layerType {
+ return @"hillshade";
+}
+
+- (void)testProperties {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+
+ MGLHillshadeStyleLayer *layer = [[MGLHillshadeStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+ XCTAssertNotEqual(layer.rawLayer, nullptr);
+ XCTAssertTrue(layer.rawLayer->is<mbgl::style::HillshadeLayer>());
+ auto rawLayer = layer.rawLayer->as<mbgl::style::HillshadeLayer>();
+
+ MGLTransition transitionTest = MGLTransitionMake(5, 4);
+
+
+ // hillshade-accent-color
+ {
+ XCTAssertTrue(rawLayer->getHillshadeAccentColor().isUndefined(),
+ @"hillshade-accent-color should be unset initially.");
+ NSExpression *defaultExpression = layer.hillshadeAccentColor;
+
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ layer.hillshadeAccentColor = constantExpression;
+ mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+ XCTAssertEqual(rawLayer->getHillshadeAccentColor(), propertyValue,
+ @"Setting hillshadeAccentColor to a constant value expression should update hillshade-accent-color.");
+ XCTAssertEqualObjects(layer.hillshadeAccentColor, constantExpression,
+ @"hillshadeAccentColor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.hillshadeAccentColor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = {{
+ { -INFINITY, { 1, 0, 0, 1 } },
+ { 18, { 1, 0, 0, 1 } },
+ }};
+ propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getHillshadeAccentColor(), propertyValue,
+ @"Setting hillshadeAccentColor to a camera expression should update hillshade-accent-color.");
+ XCTAssertEqualObjects(layer.hillshadeAccentColor, functionExpression,
+ @"hillshadeAccentColor should round-trip camera expressions.");
+
+
+
+ layer.hillshadeAccentColor = nil;
+ XCTAssertTrue(rawLayer->getHillshadeAccentColor().isUndefined(),
+ @"Unsetting hillshadeAccentColor should return hillshade-accent-color to the default value.");
+ XCTAssertEqualObjects(layer.hillshadeAccentColor, defaultExpression,
+ @"hillshadeAccentColor should return the default value after being unset.");
+
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.hillshadeAccentColor = functionExpression, NSException, NSInvalidArgumentException, @"MGLHillshadeLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.hillshadeAccentColor = functionExpression, NSException, NSInvalidArgumentException, @"MGLHillshadeLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ // Transition property test
+ layer.hillshadeAccentColorTransition = transitionTest;
+ auto toptions = rawLayer->getHillshadeAccentColorTransition();
+ XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay);
+ XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration);
+
+ MGLTransition hillshadeAccentColorTransition = layer.hillshadeAccentColorTransition;
+ XCTAssertEqual(hillshadeAccentColorTransition.delay, transitionTest.delay);
+ XCTAssertEqual(hillshadeAccentColorTransition.duration, transitionTest.duration);
+ }
+
+ // hillshade-exaggeration
+ {
+ XCTAssertTrue(rawLayer->getHillshadeExaggeration().isUndefined(),
+ @"hillshade-exaggeration should be unset initially.");
+ NSExpression *defaultExpression = layer.hillshadeExaggeration;
+
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.hillshadeExaggeration = constantExpression;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getHillshadeExaggeration(), propertyValue,
+ @"Setting hillshadeExaggeration to a constant value expression should update hillshade-exaggeration.");
+ XCTAssertEqualObjects(layer.hillshadeExaggeration, constantExpression,
+ @"hillshadeExaggeration should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.hillshadeExaggeration = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getHillshadeExaggeration(), propertyValue,
+ @"Setting hillshadeExaggeration to a camera expression should update hillshade-exaggeration.");
+ XCTAssertEqualObjects(layer.hillshadeExaggeration, functionExpression,
+ @"hillshadeExaggeration should round-trip camera expressions.");
+
+
+
+ layer.hillshadeExaggeration = nil;
+ XCTAssertTrue(rawLayer->getHillshadeExaggeration().isUndefined(),
+ @"Unsetting hillshadeExaggeration should return hillshade-exaggeration to the default value.");
+ XCTAssertEqualObjects(layer.hillshadeExaggeration, defaultExpression,
+ @"hillshadeExaggeration should return the default value after being unset.");
+
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.hillshadeExaggeration = functionExpression, NSException, NSInvalidArgumentException, @"MGLHillshadeLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.hillshadeExaggeration = functionExpression, NSException, NSInvalidArgumentException, @"MGLHillshadeLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ // Transition property test
+ layer.hillshadeExaggerationTransition = transitionTest;
+ auto toptions = rawLayer->getHillshadeExaggerationTransition();
+ XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay);
+ XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration);
+
+ MGLTransition hillshadeExaggerationTransition = layer.hillshadeExaggerationTransition;
+ XCTAssertEqual(hillshadeExaggerationTransition.delay, transitionTest.delay);
+ XCTAssertEqual(hillshadeExaggerationTransition.duration, transitionTest.duration);
+ }
+
+ // hillshade-highlight-color
+ {
+ XCTAssertTrue(rawLayer->getHillshadeHighlightColor().isUndefined(),
+ @"hillshade-highlight-color should be unset initially.");
+ NSExpression *defaultExpression = layer.hillshadeHighlightColor;
+
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ layer.hillshadeHighlightColor = constantExpression;
+ mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+ XCTAssertEqual(rawLayer->getHillshadeHighlightColor(), propertyValue,
+ @"Setting hillshadeHighlightColor to a constant value expression should update hillshade-highlight-color.");
+ XCTAssertEqualObjects(layer.hillshadeHighlightColor, constantExpression,
+ @"hillshadeHighlightColor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.hillshadeHighlightColor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = {{
+ { -INFINITY, { 1, 0, 0, 1 } },
+ { 18, { 1, 0, 0, 1 } },
+ }};
+ propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getHillshadeHighlightColor(), propertyValue,
+ @"Setting hillshadeHighlightColor to a camera expression should update hillshade-highlight-color.");
+ XCTAssertEqualObjects(layer.hillshadeHighlightColor, functionExpression,
+ @"hillshadeHighlightColor should round-trip camera expressions.");
+
+
+
+ layer.hillshadeHighlightColor = nil;
+ XCTAssertTrue(rawLayer->getHillshadeHighlightColor().isUndefined(),
+ @"Unsetting hillshadeHighlightColor should return hillshade-highlight-color to the default value.");
+ XCTAssertEqualObjects(layer.hillshadeHighlightColor, defaultExpression,
+ @"hillshadeHighlightColor should return the default value after being unset.");
+
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.hillshadeHighlightColor = functionExpression, NSException, NSInvalidArgumentException, @"MGLHillshadeLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.hillshadeHighlightColor = functionExpression, NSException, NSInvalidArgumentException, @"MGLHillshadeLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ // Transition property test
+ layer.hillshadeHighlightColorTransition = transitionTest;
+ auto toptions = rawLayer->getHillshadeHighlightColorTransition();
+ XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay);
+ XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration);
+
+ MGLTransition hillshadeHighlightColorTransition = layer.hillshadeHighlightColorTransition;
+ XCTAssertEqual(hillshadeHighlightColorTransition.delay, transitionTest.delay);
+ XCTAssertEqual(hillshadeHighlightColorTransition.duration, transitionTest.duration);
+ }
+
+ // hillshade-illumination-anchor
+ {
+ XCTAssertTrue(rawLayer->getHillshadeIlluminationAnchor().isUndefined(),
+ @"hillshade-illumination-anchor should be unset initially.");
+ NSExpression *defaultExpression = layer.hillshadeIlluminationAnchor;
+
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ layer.hillshadeIlluminationAnchor = constantExpression;
+ mbgl::style::PropertyValue<mbgl::style::HillshadeIlluminationAnchorType> propertyValue = { mbgl::style::HillshadeIlluminationAnchorType::Viewport };
+ XCTAssertEqual(rawLayer->getHillshadeIlluminationAnchor(), propertyValue,
+ @"Setting hillshadeIlluminationAnchor to a constant value expression should update hillshade-illumination-anchor.");
+ XCTAssertEqualObjects(layer.hillshadeIlluminationAnchor, constantExpression,
+ @"hillshadeIlluminationAnchor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.hillshadeIlluminationAnchor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::HillshadeIlluminationAnchorType> intervalStops = {{
+ { -INFINITY, mbgl::style::HillshadeIlluminationAnchorType::Viewport },
+ { 18, mbgl::style::HillshadeIlluminationAnchorType::Viewport },
+ }};
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::HillshadeIlluminationAnchorType> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getHillshadeIlluminationAnchor(), propertyValue,
+ @"Setting hillshadeIlluminationAnchor to a camera expression should update hillshade-illumination-anchor.");
+ XCTAssertEqualObjects(layer.hillshadeIlluminationAnchor, functionExpression,
+ @"hillshadeIlluminationAnchor should round-trip camera expressions.");
+
+
+
+ layer.hillshadeIlluminationAnchor = nil;
+ XCTAssertTrue(rawLayer->getHillshadeIlluminationAnchor().isUndefined(),
+ @"Unsetting hillshadeIlluminationAnchor should return hillshade-illumination-anchor to the default value.");
+ XCTAssertEqualObjects(layer.hillshadeIlluminationAnchor, defaultExpression,
+ @"hillshadeIlluminationAnchor should return the default value after being unset.");
+
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.hillshadeIlluminationAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLHillshadeLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.hillshadeIlluminationAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLHillshadeLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ }
+
+ // hillshade-illumination-direction
+ {
+ XCTAssertTrue(rawLayer->getHillshadeIlluminationDirection().isUndefined(),
+ @"hillshade-illumination-direction should be unset initially.");
+ NSExpression *defaultExpression = layer.hillshadeIlluminationDirection;
+
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.hillshadeIlluminationDirection = constantExpression;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getHillshadeIlluminationDirection(), propertyValue,
+ @"Setting hillshadeIlluminationDirection to a constant value expression should update hillshade-illumination-direction.");
+ XCTAssertEqualObjects(layer.hillshadeIlluminationDirection, constantExpression,
+ @"hillshadeIlluminationDirection should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.hillshadeIlluminationDirection = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getHillshadeIlluminationDirection(), propertyValue,
+ @"Setting hillshadeIlluminationDirection to a camera expression should update hillshade-illumination-direction.");
+ XCTAssertEqualObjects(layer.hillshadeIlluminationDirection, functionExpression,
+ @"hillshadeIlluminationDirection should round-trip camera expressions.");
+
+
+
+ layer.hillshadeIlluminationDirection = nil;
+ XCTAssertTrue(rawLayer->getHillshadeIlluminationDirection().isUndefined(),
+ @"Unsetting hillshadeIlluminationDirection should return hillshade-illumination-direction to the default value.");
+ XCTAssertEqualObjects(layer.hillshadeIlluminationDirection, defaultExpression,
+ @"hillshadeIlluminationDirection should return the default value after being unset.");
+
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.hillshadeIlluminationDirection = functionExpression, NSException, NSInvalidArgumentException, @"MGLHillshadeLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.hillshadeIlluminationDirection = functionExpression, NSException, NSInvalidArgumentException, @"MGLHillshadeLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ }
+
+ // hillshade-shadow-color
+ {
+ XCTAssertTrue(rawLayer->getHillshadeShadowColor().isUndefined(),
+ @"hillshade-shadow-color should be unset initially.");
+ NSExpression *defaultExpression = layer.hillshadeShadowColor;
+
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ layer.hillshadeShadowColor = constantExpression;
+ mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+ XCTAssertEqual(rawLayer->getHillshadeShadowColor(), propertyValue,
+ @"Setting hillshadeShadowColor to a constant value expression should update hillshade-shadow-color.");
+ XCTAssertEqualObjects(layer.hillshadeShadowColor, constantExpression,
+ @"hillshadeShadowColor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.hillshadeShadowColor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = {{
+ { -INFINITY, { 1, 0, 0, 1 } },
+ { 18, { 1, 0, 0, 1 } },
+ }};
+ propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getHillshadeShadowColor(), propertyValue,
+ @"Setting hillshadeShadowColor to a camera expression should update hillshade-shadow-color.");
+ XCTAssertEqualObjects(layer.hillshadeShadowColor, functionExpression,
+ @"hillshadeShadowColor should round-trip camera expressions.");
+
+
+
+ layer.hillshadeShadowColor = nil;
+ XCTAssertTrue(rawLayer->getHillshadeShadowColor().isUndefined(),
+ @"Unsetting hillshadeShadowColor should return hillshade-shadow-color to the default value.");
+ XCTAssertEqualObjects(layer.hillshadeShadowColor, defaultExpression,
+ @"hillshadeShadowColor should return the default value after being unset.");
+
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.hillshadeShadowColor = functionExpression, NSException, NSInvalidArgumentException, @"MGLHillshadeLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.hillshadeShadowColor = functionExpression, NSException, NSInvalidArgumentException, @"MGLHillshadeLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ // Transition property test
+ layer.hillshadeShadowColorTransition = transitionTest;
+ auto toptions = rawLayer->getHillshadeShadowColorTransition();
+ XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay);
+ XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration);
+
+ MGLTransition hillshadeShadowColorTransition = layer.hillshadeShadowColorTransition;
+ XCTAssertEqual(hillshadeShadowColorTransition.delay, transitionTest.delay);
+ XCTAssertEqual(hillshadeShadowColorTransition.duration, transitionTest.duration);
+ }
+}
+
+- (void)testPropertyNames {
+ [self testPropertyName:@"hillshade-accent-color" isBoolean:NO];
+ [self testPropertyName:@"hillshade-exaggeration" isBoolean:NO];
+ [self testPropertyName:@"hillshade-highlight-color" isBoolean:NO];
+ [self testPropertyName:@"hillshade-illumination-anchor" isBoolean:NO];
+ [self testPropertyName:@"hillshade-illumination-direction" isBoolean:NO];
+ [self testPropertyName:@"hillshade-shadow-color" isBoolean:NO];
+}
+
+- (void)testValueAdditions {
+ XCTAssertEqual([NSValue valueWithMGLHillshadeIlluminationAnchor:MGLHillshadeIlluminationAnchorMap].MGLHillshadeIlluminationAnchorValue, MGLHillshadeIlluminationAnchorMap);
+ XCTAssertEqual([NSValue valueWithMGLHillshadeIlluminationAnchor:MGLHillshadeIlluminationAnchorViewport].MGLHillshadeIlluminationAnchorValue, MGLHillshadeIlluminationAnchorViewport);
+}
+
+@end
diff --git a/platform/darwin/test/MGLLightTest.mm b/platform/darwin/test/MGLLightTest.mm
index de64d57851..a51c59c725 100644
--- a/platform/darwin/test/MGLLightTest.mm
+++ b/platform/darwin/test/MGLLightTest.mm
@@ -27,29 +27,28 @@
{
mbgl::style::Light light;
MGLLight *mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
- auto lightFromMGLlight = [mglLight mbglLight];
+ auto lightFromMGLLight = mglLight.mbglLight;
- XCTAssertEqual(light.getDefaultAnchor(), lightFromMGLlight.getAnchor());
- XCTAssert([mglLight.anchor isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.anchor isn’t a MGLConstantStyleValue.");
- NSValue *anchorValue = ((MGLConstantStyleValue *)mglLight.anchor).rawValue;
- XCTAssertEqual(anchorValue.MGLLightAnchorValue, MGLLightAnchorViewport);
+ XCTAssertEqual(light.getDefaultAnchor(), lightFromMGLLight.getAnchor());
+ XCTAssertEqual(mglLight.anchor.expressionType, NSConstantValueExpressionType, @"mglLight.anchor isn’t a constant value expression.");
+ XCTAssertEqualObjects(mglLight.anchor.constantValue, @"viewport");
mbgl::style::PropertyValue<mbgl::style::LightAnchorType> propertyValue = { mbgl::style::LightAnchorType::Viewport };
light.setAnchor(propertyValue);
mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
- lightFromMGLlight = [mglLight mbglLight];
+ lightFromMGLLight = mglLight.mbglLight;
- XCTAssertEqual(light.getAnchor(), lightFromMGLlight.getAnchor());
+ XCTAssertEqual(light.getAnchor(), lightFromMGLLight.getAnchor());
}
// position
{
mbgl::style::Light light;
MGLLight *mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
- auto lightFromMGLlight = [mglLight mbglLight];
+ auto lightFromMGLLight = mglLight.mbglLight;
- XCTAssertEqual(light.getDefaultPosition(), lightFromMGLlight.getPosition());
- auto positionTransition = lightFromMGLlight.getPositionTransition();
+ XCTAssertEqual(light.getDefaultPosition(), lightFromMGLLight.getPosition());
+ auto positionTransition = lightFromMGLLight.getPositionTransition();
XCTAssert(positionTransition.delay && MGLTimeIntervalFromDuration(*positionTransition.delay) == defaultTransition.delay);
XCTAssert(positionTransition.duration && MGLTimeIntervalFromDuration(*positionTransition.duration) == defaultTransition.duration);
@@ -60,10 +59,10 @@
light.setPositionTransition(transitionOptions);
mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
- lightFromMGLlight = [mglLight mbglLight];
+ lightFromMGLLight = mglLight.mbglLight;
- XCTAssertEqual(light.getPosition(), lightFromMGLlight.getPosition());
- positionTransition = lightFromMGLlight.getPositionTransition();
+ XCTAssertEqual(light.getPosition(), lightFromMGLLight.getPosition());
+ positionTransition = lightFromMGLLight.getPositionTransition();
XCTAssert(positionTransition.delay && MGLTimeIntervalFromDuration(*positionTransition.delay) == transition.delay);
XCTAssert(positionTransition.duration && MGLTimeIntervalFromDuration(*positionTransition.duration) == transition.duration);
@@ -73,10 +72,10 @@
{
mbgl::style::Light light;
MGLLight *mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
- auto lightFromMGLlight = [mglLight mbglLight];
+ auto lightFromMGLLight = mglLight.mbglLight;
- XCTAssertEqual(light.getDefaultColor(), lightFromMGLlight.getColor());
- auto colorTransition = lightFromMGLlight.getColorTransition();
+ XCTAssertEqual(light.getDefaultColor(), lightFromMGLLight.getColor());
+ auto colorTransition = lightFromMGLLight.getColorTransition();
XCTAssert(colorTransition.delay && MGLTimeIntervalFromDuration(*colorTransition.delay) == defaultTransition.delay);
XCTAssert(colorTransition.duration && MGLTimeIntervalFromDuration(*colorTransition.duration) == defaultTransition.duration);
@@ -85,10 +84,10 @@
light.setColorTransition(transitionOptions);
mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
- lightFromMGLlight = [mglLight mbglLight];
+ lightFromMGLLight = mglLight.mbglLight;
- XCTAssertEqual(light.getColor(), lightFromMGLlight.getColor());
- colorTransition = lightFromMGLlight.getColorTransition();
+ XCTAssertEqual(light.getColor(), lightFromMGLLight.getColor());
+ colorTransition = lightFromMGLLight.getColorTransition();
XCTAssert(colorTransition.delay && MGLTimeIntervalFromDuration(*colorTransition.delay) == transition.delay);
XCTAssert(colorTransition.duration && MGLTimeIntervalFromDuration(*colorTransition.duration) == transition.duration);
@@ -98,10 +97,10 @@
{
mbgl::style::Light light;
MGLLight *mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
- auto lightFromMGLlight = [mglLight mbglLight];
+ auto lightFromMGLLight = mglLight.mbglLight;
- XCTAssertEqual(light.getDefaultIntensity(), lightFromMGLlight.getIntensity());
- auto intensityTransition = lightFromMGLlight.getIntensityTransition();
+ XCTAssertEqual(light.getDefaultIntensity(), lightFromMGLLight.getIntensity());
+ auto intensityTransition = lightFromMGLLight.getIntensityTransition();
XCTAssert(intensityTransition.delay && MGLTimeIntervalFromDuration(*intensityTransition.delay) == defaultTransition.delay);
XCTAssert(intensityTransition.duration && MGLTimeIntervalFromDuration(*intensityTransition.duration) == defaultTransition.duration);
@@ -110,10 +109,10 @@
light.setIntensityTransition(transitionOptions);
mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
- lightFromMGLlight = [mglLight mbglLight];
+ lightFromMGLLight = mglLight.mbglLight;
- XCTAssertEqual(light.getIntensity(), lightFromMGLlight.getIntensity());
- intensityTransition = lightFromMGLlight.getIntensityTransition();
+ XCTAssertEqual(light.getIntensity(), lightFromMGLLight.getIntensity());
+ intensityTransition = lightFromMGLLight.getIntensityTransition();
XCTAssert(intensityTransition.delay && MGLTimeIntervalFromDuration(*intensityTransition.delay) == transition.delay);
XCTAssert(intensityTransition.duration && MGLTimeIntervalFromDuration(*intensityTransition.duration) == transition.duration);
diff --git a/platform/darwin/test/MGLLightTest.mm.ejs b/platform/darwin/test/MGLLightTest.mm.ejs
index 5b1f27d8d1..35ff58b6d5 100644
--- a/platform/darwin/test/MGLLightTest.mm.ejs
+++ b/platform/darwin/test/MGLLightTest.mm.ejs
@@ -32,19 +32,18 @@
{
mbgl::style::Light light;
MGLLight *mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
- auto lightFromMGLlight = [mglLight mbglLight];
+ auto lightFromMGLLight = mglLight.mbglLight;
- XCTAssertEqual(light.getDefault<%- camelize(property.name) -%>(), lightFromMGLlight.get<%- camelize(property.name) -%>());
+ XCTAssertEqual(light.getDefault<%- camelize(property.name) -%>(), lightFromMGLLight.get<%- camelize(property.name) -%>());
<% if (property.transition) { -%>
- auto <%- camelizeWithLeadingLowercase(property.name) -%>Transition = lightFromMGLlight.get<%- camelize(property.name) -%>Transition();
+ auto <%- camelizeWithLeadingLowercase(property.name) -%>Transition = lightFromMGLLight.get<%- camelize(property.name) -%>Transition();
XCTAssert(<%- camelizeWithLeadingLowercase(property.name) -%>Transition.delay && MGLTimeIntervalFromDuration(*<%- camelizeWithLeadingLowercase(property.name) -%>Transition.delay) == defaultTransition.delay);
XCTAssert(<%- camelizeWithLeadingLowercase(property.name) -%>Transition.duration && MGLTimeIntervalFromDuration(*<%- camelizeWithLeadingLowercase(property.name) -%>Transition.duration) == defaultTransition.duration);
<% } -%>
<% if (property.type == "enum" && property.default) { -%>
- XCTAssert([mglLight.<%- camelizeWithLeadingLowercase(property.name) -%> isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.<%- camelizeWithLeadingLowercase(property.name) -%> isn’t a MGLConstantStyleValue.");
- NSValue *<%- camelizeWithLeadingLowercase(property.name) -%>Value = ((MGLConstantStyleValue *)mglLight.<%- camelizeWithLeadingLowercase(property.name) -%>).rawValue;
- XCTAssertEqual(<%- camelizeWithLeadingLowercase(property.name) -%>Value.MGLLight<%- camelize(property.name) -%>Value, MGLLight<%- camelize(property.name) -%><%- camelize(property.default) -%>);
+ XCTAssertEqual(mglLight.<%- camelizeWithLeadingLowercase(property.name) -%>.expressionType, NSConstantValueExpressionType, @"mglLight.<%- camelizeWithLeadingLowercase(property.name) -%> isn’t a constant value expression.");
+ XCTAssertEqualObjects(mglLight.<%- camelizeWithLeadingLowercase(property.name) -%>.constantValue, @"<%- property.default -%>");
<% } -%>
<% if (property.type == "array") { -%>
@@ -60,11 +59,11 @@
<% } -%>
mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
- lightFromMGLlight = [mglLight mbglLight];
+ lightFromMGLLight = mglLight.mbglLight;
- XCTAssertEqual(light.get<%- camelize(property.name) -%>(), lightFromMGLlight.get<%- camelize(property.name) -%>());
+ XCTAssertEqual(light.get<%- camelize(property.name) -%>(), lightFromMGLLight.get<%- camelize(property.name) -%>());
<% if (property.transition) { -%>
- <%- camelizeWithLeadingLowercase(property.name) -%>Transition = lightFromMGLlight.get<%- camelize(property.name) -%>Transition();
+ <%- camelizeWithLeadingLowercase(property.name) -%>Transition = lightFromMGLLight.get<%- camelize(property.name) -%>Transition();
XCTAssert(<%- camelizeWithLeadingLowercase(property.name) -%>Transition.delay && MGLTimeIntervalFromDuration(*<%- camelizeWithLeadingLowercase(property.name) -%>Transition.delay) == transition.delay);
XCTAssert(<%- camelizeWithLeadingLowercase(property.name) -%>Transition.duration && MGLTimeIntervalFromDuration(*<%- camelizeWithLeadingLowercase(property.name) -%>Transition.duration) == transition.duration);
diff --git a/platform/darwin/test/MGLLineStyleLayerTests.mm b/platform/darwin/test/MGLLineStyleLayerTests.mm
index 7e7926e22e..5490278e98 100644
--- a/platform/darwin/test/MGLLineStyleLayerTests.mm
+++ b/platform/darwin/test/MGLLineStyleLayerTests.mm
@@ -30,8 +30,8 @@
XCTAssertNil(layer.sourceLayerIdentifier);
XCTAssertNil(layer.predicate);
- layer.predicate = [NSPredicate predicateWithValue:NO];
- XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
+ layer.predicate = [NSPredicate predicateWithFormat:@"$featureIdentifier = 1"];
+ XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithFormat:@"$featureIdentifier = 1"]);
layer.predicate = nil;
XCTAssertNil(layer.predicate);
}
@@ -52,72 +52,81 @@
{
XCTAssertTrue(rawLayer->getLineCap().isUndefined(),
@"line-cap should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineCap;
+ NSExpression *defaultExpression = layer.lineCap;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineCap:MGLLineCapSquare]];
- layer.lineCap = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'square'"];
+ layer.lineCap = constantExpression;
mbgl::style::PropertyValue<mbgl::style::LineCapType> propertyValue = { mbgl::style::LineCapType::Square };
XCTAssertEqual(rawLayer->getLineCap(), propertyValue,
- @"Setting lineCap to a constant value should update line-cap.");
- XCTAssertEqualObjects(layer.lineCap, constantStyleValue,
- @"lineCap should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.lineCap = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::LineCapType> intervalStops = { {{18, mbgl::style::LineCapType::Square}} };
+ @"Setting lineCap to a constant value expression should update line-cap.");
+ XCTAssertEqualObjects(layer.lineCap, constantExpression,
+ @"lineCap should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'square'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.lineCap = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::LineCapType> intervalStops = {{
+ { -INFINITY, mbgl::style::LineCapType::Square },
+ { 18, mbgl::style::LineCapType::Square },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::LineCapType> { intervalStops };
XCTAssertEqual(rawLayer->getLineCap(), propertyValue,
- @"Setting lineCap to a camera function should update line-cap.");
- XCTAssertEqualObjects(layer.lineCap, functionStyleValue,
- @"lineCap should round-trip camera functions.");
+ @"Setting lineCap to a camera expression should update line-cap.");
+ XCTAssertEqualObjects(layer.lineCap, functionExpression,
+ @"lineCap should round-trip camera expressions.");
layer.lineCap = nil;
XCTAssertTrue(rawLayer->getLineCap().isUndefined(),
@"Unsetting lineCap should return line-cap to the default value.");
- XCTAssertEqualObjects(layer.lineCap, defaultStyleValue,
+ XCTAssertEqualObjects(layer.lineCap, defaultExpression,
@"lineCap should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineCap = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineCap = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.lineCap = functionExpression, NSException, NSInvalidArgumentException, @"MGLLineLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.lineCap = functionExpression, NSException, NSInvalidArgumentException, @"MGLLineLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// line-join
{
XCTAssertTrue(rawLayer->getLineJoin().isUndefined(),
@"line-join should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineJoin;
+ NSExpression *defaultExpression = layer.lineJoin;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineJoin:MGLLineJoinMiter]];
- layer.lineJoin = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'miter'"];
+ layer.lineJoin = constantExpression;
mbgl::style::DataDrivenPropertyValue<mbgl::style::LineJoinType> propertyValue = { mbgl::style::LineJoinType::Miter };
XCTAssertEqual(rawLayer->getLineJoin(), propertyValue,
- @"Setting lineJoin to a constant value should update line-join.");
- XCTAssertEqualObjects(layer.lineJoin, constantStyleValue,
- @"lineJoin should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.lineJoin = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::LineJoinType> intervalStops = { {{18, mbgl::style::LineJoinType::Miter}} };
+ @"Setting lineJoin to a constant value expression should update line-join.");
+ XCTAssertEqualObjects(layer.lineJoin, constantExpression,
+ @"lineJoin should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'miter'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.lineJoin = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::LineJoinType> intervalStops = {{
+ { -INFINITY, mbgl::style::LineJoinType::Miter },
+ { 18, mbgl::style::LineJoinType::Miter },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::LineJoinType> { intervalStops };
XCTAssertEqual(rawLayer->getLineJoin(), propertyValue,
- @"Setting lineJoin to a camera function should update line-join.");
- XCTAssertEqualObjects(layer.lineJoin, functionStyleValue,
- @"lineJoin should round-trip camera functions.");
+ @"Setting lineJoin to a camera expression should update line-join.");
+ XCTAssertEqualObjects(layer.lineJoin, functionExpression,
+ @"lineJoin should round-trip camera expressions.");
layer.lineJoin = nil;
XCTAssertTrue(rawLayer->getLineJoin().isUndefined(),
@"Unsetting lineJoin should return line-join to the default value.");
- XCTAssertEqualObjects(layer.lineJoin, defaultStyleValue,
+ XCTAssertEqualObjects(layer.lineJoin, defaultExpression,
@"lineJoin should return the default value after being unset.");
}
@@ -125,118 +134,133 @@
{
XCTAssertTrue(rawLayer->getLineMiterLimit().isUndefined(),
@"line-miter-limit should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineMiterLimit;
+ NSExpression *defaultExpression = layer.lineMiterLimit;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.lineMiterLimit = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.lineMiterLimit = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineMiterLimit(), propertyValue,
- @"Setting lineMiterLimit to a constant value should update line-miter-limit.");
- XCTAssertEqualObjects(layer.lineMiterLimit, constantStyleValue,
- @"lineMiterLimit should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.lineMiterLimit = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting lineMiterLimit to a constant value expression should update line-miter-limit.");
+ XCTAssertEqualObjects(layer.lineMiterLimit, constantExpression,
+ @"lineMiterLimit should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.lineMiterLimit = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getLineMiterLimit(), propertyValue,
- @"Setting lineMiterLimit to a camera function should update line-miter-limit.");
- XCTAssertEqualObjects(layer.lineMiterLimit, functionStyleValue,
- @"lineMiterLimit should round-trip camera functions.");
+ @"Setting lineMiterLimit to a camera expression should update line-miter-limit.");
+ XCTAssertEqualObjects(layer.lineMiterLimit, functionExpression,
+ @"lineMiterLimit should round-trip camera expressions.");
layer.lineMiterLimit = nil;
XCTAssertTrue(rawLayer->getLineMiterLimit().isUndefined(),
@"Unsetting lineMiterLimit should return line-miter-limit to the default value.");
- XCTAssertEqualObjects(layer.lineMiterLimit, defaultStyleValue,
+ XCTAssertEqualObjects(layer.lineMiterLimit, defaultExpression,
@"lineMiterLimit should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineMiterLimit = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineMiterLimit = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.lineMiterLimit = functionExpression, NSException, NSInvalidArgumentException, @"MGLLineLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.lineMiterLimit = functionExpression, NSException, NSInvalidArgumentException, @"MGLLineLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// line-round-limit
{
XCTAssertTrue(rawLayer->getLineRoundLimit().isUndefined(),
@"line-round-limit should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineRoundLimit;
+ NSExpression *defaultExpression = layer.lineRoundLimit;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.lineRoundLimit = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.lineRoundLimit = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineRoundLimit(), propertyValue,
- @"Setting lineRoundLimit to a constant value should update line-round-limit.");
- XCTAssertEqualObjects(layer.lineRoundLimit, constantStyleValue,
- @"lineRoundLimit should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.lineRoundLimit = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting lineRoundLimit to a constant value expression should update line-round-limit.");
+ XCTAssertEqualObjects(layer.lineRoundLimit, constantExpression,
+ @"lineRoundLimit should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.lineRoundLimit = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getLineRoundLimit(), propertyValue,
- @"Setting lineRoundLimit to a camera function should update line-round-limit.");
- XCTAssertEqualObjects(layer.lineRoundLimit, functionStyleValue,
- @"lineRoundLimit should round-trip camera functions.");
+ @"Setting lineRoundLimit to a camera expression should update line-round-limit.");
+ XCTAssertEqualObjects(layer.lineRoundLimit, functionExpression,
+ @"lineRoundLimit should round-trip camera expressions.");
layer.lineRoundLimit = nil;
XCTAssertTrue(rawLayer->getLineRoundLimit().isUndefined(),
@"Unsetting lineRoundLimit should return line-round-limit to the default value.");
- XCTAssertEqualObjects(layer.lineRoundLimit, defaultStyleValue,
+ XCTAssertEqualObjects(layer.lineRoundLimit, defaultExpression,
@"lineRoundLimit should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineRoundLimit = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineRoundLimit = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.lineRoundLimit = functionExpression, NSException, NSInvalidArgumentException, @"MGLLineLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.lineRoundLimit = functionExpression, NSException, NSInvalidArgumentException, @"MGLLineLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// line-blur
{
XCTAssertTrue(rawLayer->getLineBlur().isUndefined(),
@"line-blur should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineBlur;
+ NSExpression *defaultExpression = layer.lineBlur;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.lineBlur = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.lineBlur = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineBlur(), propertyValue,
- @"Setting lineBlur to a constant value should update line-blur.");
- XCTAssertEqualObjects(layer.lineBlur, constantStyleValue,
- @"lineBlur should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.lineBlur = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting lineBlur to a constant value expression should update line-blur.");
+ XCTAssertEqualObjects(layer.lineBlur, constantExpression,
+ @"lineBlur should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.lineBlur = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getLineBlur(), propertyValue,
- @"Setting lineBlur to a camera function should update line-blur.");
- XCTAssertEqualObjects(layer.lineBlur, functionStyleValue,
- @"lineBlur should round-trip camera functions.");
+ @"Setting lineBlur to a camera expression should update line-blur.");
+ XCTAssertEqualObjects(layer.lineBlur, functionExpression,
+ @"lineBlur should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.lineBlur = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.lineBlur = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getLineBlur(), propertyValue,
- @"Setting lineBlur to a source function should update line-blur.");
- XCTAssertEqualObjects(layer.lineBlur, functionStyleValue,
- @"lineBlur should round-trip source functions.");
+ @"Setting lineBlur to a data expression should update line-blur.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.lineBlur, pedanticFunctionExpression,
+ @"lineBlur should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.lineBlur = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.lineBlur = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -244,15 +268,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getLineBlur(), propertyValue,
- @"Setting lineBlur to a composite function should update line-blur.");
- XCTAssertEqualObjects(layer.lineBlur, functionStyleValue,
- @"lineBlur should round-trip composite functions.");
+ @"Setting lineBlur to a camera-data expression should update line-blur.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.lineBlur, pedanticFunctionExpression,
+ @"lineBlur should round-trip camera-data expressions.");
layer.lineBlur = nil;
XCTAssertTrue(rawLayer->getLineBlur().isUndefined(),
@"Unsetting lineBlur should return line-blur to the default value.");
- XCTAssertEqualObjects(layer.lineBlur, defaultStyleValue,
+ XCTAssertEqualObjects(layer.lineBlur, defaultExpression,
@"lineBlur should return the default value after being unset.");
// Transition property test
layer.lineBlurTransition = transitionTest;
@@ -269,40 +294,45 @@
{
XCTAssertTrue(rawLayer->getLineColor().isUndefined(),
@"line-color should be unset initially.");
- MGLStyleValue<MGLColor *> *defaultStyleValue = layer.lineColor;
+ NSExpression *defaultExpression = layer.lineColor;
- MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.lineColor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ layer.lineColor = constantExpression;
mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getLineColor(), propertyValue,
- @"Setting lineColor to a constant value should update line-color.");
- XCTAssertEqualObjects(layer.lineColor, constantStyleValue,
- @"lineColor should round-trip constant values.");
-
- MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.lineColor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ @"Setting lineColor to a constant value expression should update line-color.");
+ XCTAssertEqualObjects(layer.lineColor, constantExpression,
+ @"lineColor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.lineColor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = {{
+ { -INFINITY, { 1, 0, 0, 1 } },
+ { 18, { 1, 0, 0, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
XCTAssertEqual(rawLayer->getLineColor(), propertyValue,
- @"Setting lineColor to a camera function should update line-color.");
- XCTAssertEqualObjects(layer.lineColor, functionStyleValue,
- @"lineColor should round-trip camera functions.");
+ @"Setting lineColor to a camera expression should update line-color.");
+ XCTAssertEqualObjects(layer.lineColor, functionExpression,
+ @"lineColor should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.lineColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.lineColor = functionExpression;
mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getLineColor(), propertyValue,
- @"Setting lineColor to a source function should update line-color.");
- XCTAssertEqualObjects(layer.lineColor, functionStyleValue,
- @"lineColor should round-trip source functions.");
+ @"Setting lineColor to a data expression should update line-color.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.lineColor, pedanticFunctionExpression,
+ @"lineColor should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.lineColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.lineColor = functionExpression;
std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -310,15 +340,16 @@
propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getLineColor(), propertyValue,
- @"Setting lineColor to a composite function should update line-color.");
- XCTAssertEqualObjects(layer.lineColor, functionStyleValue,
- @"lineColor should round-trip composite functions.");
+ @"Setting lineColor to a camera-data expression should update line-color.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.lineColor, pedanticFunctionExpression,
+ @"lineColor should round-trip camera-data expressions.");
layer.lineColor = nil;
XCTAssertTrue(rawLayer->getLineColor().isUndefined(),
@"Unsetting lineColor should return line-color to the default value.");
- XCTAssertEqualObjects(layer.lineColor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.lineColor, defaultExpression,
@"lineColor should return the default value after being unset.");
// Transition property test
layer.lineColorTransition = transitionTest;
@@ -335,79 +366,89 @@
{
XCTAssertTrue(rawLayer->getLineDasharray().isUndefined(),
@"line-dasharray should be unset initially.");
- MGLStyleValue<NSArray<NSNumber *> *> *defaultStyleValue = layer.lineDashPattern;
+ NSExpression *defaultExpression = layer.lineDashPattern;
- MGLStyleValue<NSArray<NSNumber *> *> *constantStyleValue = [MGLStyleValue<NSArray<NSNumber *> *> valueWithRawValue:@[@1, @2]];
- layer.lineDashPattern = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"{1, 2}"];
+ layer.lineDashPattern = constantExpression;
mbgl::style::PropertyValue<std::vector<float>> propertyValue = { {1, 2} };
XCTAssertEqual(rawLayer->getLineDasharray(), propertyValue,
- @"Setting lineDashPattern to a constant value should update line-dasharray.");
- XCTAssertEqualObjects(layer.lineDashPattern, constantStyleValue,
- @"lineDashPattern should round-trip constant values.");
-
- MGLStyleValue<NSArray<NSNumber *> *> * functionStyleValue = [MGLStyleValue<NSArray<NSNumber *> *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.lineDashPattern = functionStyleValue;
-
- mbgl::style::IntervalStops<std::vector<float>> intervalStops = { {{18, {1, 2}}} };
+ @"Setting lineDashPattern to a constant value expression should update line-dasharray.");
+ XCTAssertEqualObjects(layer.lineDashPattern, constantExpression,
+ @"lineDashPattern should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"{1, 2}"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.lineDashPattern = functionExpression;
+
+ mbgl::style::IntervalStops<std::vector<float>> intervalStops = {{
+ { -INFINITY, {1, 2} },
+ { 18, {1, 2} },
+ }};
propertyValue = mbgl::style::CameraFunction<std::vector<float>> { intervalStops };
XCTAssertEqual(rawLayer->getLineDasharray(), propertyValue,
- @"Setting lineDashPattern to a camera function should update line-dasharray.");
- XCTAssertEqualObjects(layer.lineDashPattern, functionStyleValue,
- @"lineDashPattern should round-trip camera functions.");
+ @"Setting lineDashPattern to a camera expression should update line-dasharray.");
+ XCTAssertEqualObjects(layer.lineDashPattern, functionExpression,
+ @"lineDashPattern should round-trip camera expressions.");
layer.lineDashPattern = nil;
XCTAssertTrue(rawLayer->getLineDasharray().isUndefined(),
@"Unsetting lineDashPattern should return line-dasharray to the default value.");
- XCTAssertEqualObjects(layer.lineDashPattern, defaultStyleValue,
+ XCTAssertEqualObjects(layer.lineDashPattern, defaultExpression,
@"lineDashPattern should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSArray<NSNumber *> *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineDashPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSArray<NSNumber *> *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineDashPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.lineDashPattern = functionExpression, NSException, NSInvalidArgumentException, @"MGLLineLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.lineDashPattern = functionExpression, NSException, NSInvalidArgumentException, @"MGLLineLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// line-gap-width
{
XCTAssertTrue(rawLayer->getLineGapWidth().isUndefined(),
@"line-gap-width should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineGapWidth;
+ NSExpression *defaultExpression = layer.lineGapWidth;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.lineGapWidth = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.lineGapWidth = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue,
- @"Setting lineGapWidth to a constant value should update line-gap-width.");
- XCTAssertEqualObjects(layer.lineGapWidth, constantStyleValue,
- @"lineGapWidth should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.lineGapWidth = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting lineGapWidth to a constant value expression should update line-gap-width.");
+ XCTAssertEqualObjects(layer.lineGapWidth, constantExpression,
+ @"lineGapWidth should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.lineGapWidth = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue,
- @"Setting lineGapWidth to a camera function should update line-gap-width.");
- XCTAssertEqualObjects(layer.lineGapWidth, functionStyleValue,
- @"lineGapWidth should round-trip camera functions.");
+ @"Setting lineGapWidth to a camera expression should update line-gap-width.");
+ XCTAssertEqualObjects(layer.lineGapWidth, functionExpression,
+ @"lineGapWidth should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.lineGapWidth = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.lineGapWidth = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue,
- @"Setting lineGapWidth to a source function should update line-gap-width.");
- XCTAssertEqualObjects(layer.lineGapWidth, functionStyleValue,
- @"lineGapWidth should round-trip source functions.");
+ @"Setting lineGapWidth to a data expression should update line-gap-width.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.lineGapWidth, pedanticFunctionExpression,
+ @"lineGapWidth should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.lineGapWidth = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.lineGapWidth = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -415,15 +456,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue,
- @"Setting lineGapWidth to a composite function should update line-gap-width.");
- XCTAssertEqualObjects(layer.lineGapWidth, functionStyleValue,
- @"lineGapWidth should round-trip composite functions.");
+ @"Setting lineGapWidth to a camera-data expression should update line-gap-width.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.lineGapWidth, pedanticFunctionExpression,
+ @"lineGapWidth should round-trip camera-data expressions.");
layer.lineGapWidth = nil;
XCTAssertTrue(rawLayer->getLineGapWidth().isUndefined(),
@"Unsetting lineGapWidth should return line-gap-width to the default value.");
- XCTAssertEqualObjects(layer.lineGapWidth, defaultStyleValue,
+ XCTAssertEqualObjects(layer.lineGapWidth, defaultExpression,
@"lineGapWidth should return the default value after being unset.");
// Transition property test
layer.lineGapWidthTransition = transitionTest;
@@ -440,40 +482,45 @@
{
XCTAssertTrue(rawLayer->getLineOffset().isUndefined(),
@"line-offset should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineOffset;
+ NSExpression *defaultExpression = layer.lineOffset;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.lineOffset = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.lineOffset = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineOffset(), propertyValue,
- @"Setting lineOffset to a constant value should update line-offset.");
- XCTAssertEqualObjects(layer.lineOffset, constantStyleValue,
- @"lineOffset should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.lineOffset = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting lineOffset to a constant value expression should update line-offset.");
+ XCTAssertEqualObjects(layer.lineOffset, constantExpression,
+ @"lineOffset should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.lineOffset = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getLineOffset(), propertyValue,
- @"Setting lineOffset to a camera function should update line-offset.");
- XCTAssertEqualObjects(layer.lineOffset, functionStyleValue,
- @"lineOffset should round-trip camera functions.");
+ @"Setting lineOffset to a camera expression should update line-offset.");
+ XCTAssertEqualObjects(layer.lineOffset, functionExpression,
+ @"lineOffset should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.lineOffset = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.lineOffset = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getLineOffset(), propertyValue,
- @"Setting lineOffset to a source function should update line-offset.");
- XCTAssertEqualObjects(layer.lineOffset, functionStyleValue,
- @"lineOffset should round-trip source functions.");
+ @"Setting lineOffset to a data expression should update line-offset.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.lineOffset, pedanticFunctionExpression,
+ @"lineOffset should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.lineOffset = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.lineOffset = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -481,15 +528,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getLineOffset(), propertyValue,
- @"Setting lineOffset to a composite function should update line-offset.");
- XCTAssertEqualObjects(layer.lineOffset, functionStyleValue,
- @"lineOffset should round-trip composite functions.");
+ @"Setting lineOffset to a camera-data expression should update line-offset.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.lineOffset, pedanticFunctionExpression,
+ @"lineOffset should round-trip camera-data expressions.");
layer.lineOffset = nil;
XCTAssertTrue(rawLayer->getLineOffset().isUndefined(),
@"Unsetting lineOffset should return line-offset to the default value.");
- XCTAssertEqualObjects(layer.lineOffset, defaultStyleValue,
+ XCTAssertEqualObjects(layer.lineOffset, defaultExpression,
@"lineOffset should return the default value after being unset.");
// Transition property test
layer.lineOffsetTransition = transitionTest;
@@ -506,40 +554,45 @@
{
XCTAssertTrue(rawLayer->getLineOpacity().isUndefined(),
@"line-opacity should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineOpacity;
+ NSExpression *defaultExpression = layer.lineOpacity;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.lineOpacity = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.lineOpacity = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue,
- @"Setting lineOpacity to a constant value should update line-opacity.");
- XCTAssertEqualObjects(layer.lineOpacity, constantStyleValue,
- @"lineOpacity should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.lineOpacity = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting lineOpacity to a constant value expression should update line-opacity.");
+ XCTAssertEqualObjects(layer.lineOpacity, constantExpression,
+ @"lineOpacity should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.lineOpacity = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue,
- @"Setting lineOpacity to a camera function should update line-opacity.");
- XCTAssertEqualObjects(layer.lineOpacity, functionStyleValue,
- @"lineOpacity should round-trip camera functions.");
+ @"Setting lineOpacity to a camera expression should update line-opacity.");
+ XCTAssertEqualObjects(layer.lineOpacity, functionExpression,
+ @"lineOpacity should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.lineOpacity = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.lineOpacity = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue,
- @"Setting lineOpacity to a source function should update line-opacity.");
- XCTAssertEqualObjects(layer.lineOpacity, functionStyleValue,
- @"lineOpacity should round-trip source functions.");
+ @"Setting lineOpacity to a data expression should update line-opacity.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.lineOpacity, pedanticFunctionExpression,
+ @"lineOpacity should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.lineOpacity = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.lineOpacity = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -547,15 +600,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue,
- @"Setting lineOpacity to a composite function should update line-opacity.");
- XCTAssertEqualObjects(layer.lineOpacity, functionStyleValue,
- @"lineOpacity should round-trip composite functions.");
+ @"Setting lineOpacity to a camera-data expression should update line-opacity.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.lineOpacity, pedanticFunctionExpression,
+ @"lineOpacity should round-trip camera-data expressions.");
layer.lineOpacity = nil;
XCTAssertTrue(rawLayer->getLineOpacity().isUndefined(),
@"Unsetting lineOpacity should return line-opacity to the default value.");
- XCTAssertEqualObjects(layer.lineOpacity, defaultStyleValue,
+ XCTAssertEqualObjects(layer.lineOpacity, defaultExpression,
@"lineOpacity should return the default value after being unset.");
// Transition property test
layer.lineOpacityTransition = transitionTest;
@@ -572,39 +626,44 @@
{
XCTAssertTrue(rawLayer->getLinePattern().isUndefined(),
@"line-pattern should be unset initially.");
- MGLStyleValue<NSString *> *defaultStyleValue = layer.linePattern;
+ NSExpression *defaultExpression = layer.linePattern;
- MGLStyleValue<NSString *> *constantStyleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Line Pattern"];
- layer.linePattern = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'Line Pattern'"];
+ layer.linePattern = constantExpression;
mbgl::style::PropertyValue<std::string> propertyValue = { "Line Pattern" };
XCTAssertEqual(rawLayer->getLinePattern(), propertyValue,
- @"Setting linePattern to a constant value should update line-pattern.");
- XCTAssertEqualObjects(layer.linePattern, constantStyleValue,
- @"linePattern should round-trip constant values.");
-
- MGLStyleValue<NSString *> * functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.linePattern = functionStyleValue;
-
- mbgl::style::IntervalStops<std::string> intervalStops = { {{18, "Line Pattern"}} };
+ @"Setting linePattern to a constant value expression should update line-pattern.");
+ XCTAssertEqualObjects(layer.linePattern, constantExpression,
+ @"linePattern should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'Line Pattern'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.linePattern = functionExpression;
+
+ mbgl::style::IntervalStops<std::string> intervalStops = {{
+ { -INFINITY, "Line Pattern" },
+ { 18, "Line Pattern" },
+ }};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
XCTAssertEqual(rawLayer->getLinePattern(), propertyValue,
- @"Setting linePattern to a camera function should update line-pattern.");
- XCTAssertEqualObjects(layer.linePattern, functionStyleValue,
- @"linePattern should round-trip camera functions.");
+ @"Setting linePattern to a camera expression should update line-pattern.");
+ XCTAssertEqualObjects(layer.linePattern, functionExpression,
+ @"linePattern should round-trip camera expressions.");
layer.linePattern = nil;
XCTAssertTrue(rawLayer->getLinePattern().isUndefined(),
@"Unsetting linePattern should return line-pattern to the default value.");
- XCTAssertEqualObjects(layer.linePattern, defaultStyleValue,
+ XCTAssertEqualObjects(layer.linePattern, defaultExpression,
@"linePattern should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.linePattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.linePattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.linePattern = functionExpression, NSException, NSInvalidArgumentException, @"MGLLineLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.linePattern = functionExpression, NSException, NSInvalidArgumentException, @"MGLLineLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
// Transition property test
layer.linePatternTransition = transitionTest;
auto toptions = rawLayer->getLinePatternTransition();
@@ -620,124 +679,139 @@
{
XCTAssertTrue(rawLayer->getLineTranslate().isUndefined(),
@"line-translate should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineTranslation;
+ NSExpression *defaultExpression = layer.lineTranslation;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@",
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
- layer.lineTranslation = constantStyleValue;
+ layer.lineTranslation = constantExpression;
mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getLineTranslate(), propertyValue,
- @"Setting lineTranslation to a constant value should update line-translate.");
- XCTAssertEqualObjects(layer.lineTranslation, constantStyleValue,
- @"lineTranslation should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.lineTranslation = functionStyleValue;
-
- mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} };
+ @"Setting lineTranslation to a constant value expression should update line-translate.");
+ XCTAssertEqualObjects(layer.lineTranslation, constantExpression,
+ @"lineTranslation should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"{1, 1}"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.lineTranslation = functionExpression;
+
+ mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = {{
+ { -INFINITY, { 1, 1 } },
+ { 18, { 1, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
XCTAssertEqual(rawLayer->getLineTranslate(), propertyValue,
- @"Setting lineTranslation to a camera function should update line-translate.");
- XCTAssertEqualObjects(layer.lineTranslation, functionStyleValue,
- @"lineTranslation should round-trip camera functions.");
+ @"Setting lineTranslation to a camera expression should update line-translate.");
+ XCTAssertEqualObjects(layer.lineTranslation, functionExpression,
+ @"lineTranslation should round-trip camera expressions.");
layer.lineTranslation = nil;
XCTAssertTrue(rawLayer->getLineTranslate().isUndefined(),
@"Unsetting lineTranslation should return line-translate to the default value.");
- XCTAssertEqualObjects(layer.lineTranslation, defaultStyleValue,
+ XCTAssertEqualObjects(layer.lineTranslation, defaultExpression,
@"lineTranslation should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.lineTranslation = functionExpression, NSException, NSInvalidArgumentException, @"MGLLineLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.lineTranslation = functionExpression, NSException, NSInvalidArgumentException, @"MGLLineLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// line-translate-anchor
{
XCTAssertTrue(rawLayer->getLineTranslateAnchor().isUndefined(),
@"line-translate-anchor should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineTranslationAnchor;
+ NSExpression *defaultExpression = layer.lineTranslationAnchor;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineTranslationAnchor:MGLLineTranslationAnchorViewport]];
- layer.lineTranslationAnchor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ layer.lineTranslationAnchor = constantExpression;
mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
XCTAssertEqual(rawLayer->getLineTranslateAnchor(), propertyValue,
- @"Setting lineTranslationAnchor to a constant value should update line-translate-anchor.");
- XCTAssertEqualObjects(layer.lineTranslationAnchor, constantStyleValue,
- @"lineTranslationAnchor should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.lineTranslationAnchor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} };
+ @"Setting lineTranslationAnchor to a constant value expression should update line-translate-anchor.");
+ XCTAssertEqualObjects(layer.lineTranslationAnchor, constantExpression,
+ @"lineTranslationAnchor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.lineTranslationAnchor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = {{
+ { -INFINITY, mbgl::style::TranslateAnchorType::Viewport },
+ { 18, mbgl::style::TranslateAnchorType::Viewport },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
XCTAssertEqual(rawLayer->getLineTranslateAnchor(), propertyValue,
- @"Setting lineTranslationAnchor to a camera function should update line-translate-anchor.");
- XCTAssertEqualObjects(layer.lineTranslationAnchor, functionStyleValue,
- @"lineTranslationAnchor should round-trip camera functions.");
+ @"Setting lineTranslationAnchor to a camera expression should update line-translate-anchor.");
+ XCTAssertEqualObjects(layer.lineTranslationAnchor, functionExpression,
+ @"lineTranslationAnchor should round-trip camera expressions.");
layer.lineTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getLineTranslateAnchor().isUndefined(),
@"Unsetting lineTranslationAnchor should return line-translate-anchor to the default value.");
- XCTAssertEqualObjects(layer.lineTranslationAnchor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.lineTranslationAnchor, defaultExpression,
@"lineTranslationAnchor should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.lineTranslationAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLLineLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.lineTranslationAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLLineLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// line-width
{
XCTAssertTrue(rawLayer->getLineWidth().isUndefined(),
@"line-width should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineWidth;
+ NSExpression *defaultExpression = layer.lineWidth;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.lineWidth = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.lineWidth = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
- @"Setting lineWidth to a constant value should update line-width.");
- XCTAssertEqualObjects(layer.lineWidth, constantStyleValue,
- @"lineWidth should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.lineWidth = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting lineWidth to a constant value expression should update line-width.");
+ XCTAssertEqualObjects(layer.lineWidth, constantExpression,
+ @"lineWidth should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.lineWidth = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
- @"Setting lineWidth to a camera function should update line-width.");
- XCTAssertEqualObjects(layer.lineWidth, functionStyleValue,
- @"lineWidth should round-trip camera functions.");
+ @"Setting lineWidth to a camera expression should update line-width.");
+ XCTAssertEqualObjects(layer.lineWidth, functionExpression,
+ @"lineWidth should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.lineWidth = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.lineWidth = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
- @"Setting lineWidth to a source function should update line-width.");
- XCTAssertEqualObjects(layer.lineWidth, functionStyleValue,
- @"lineWidth should round-trip source functions.");
+ @"Setting lineWidth to a data expression should update line-width.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.lineWidth, pedanticFunctionExpression,
+ @"lineWidth should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.lineWidth = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.lineWidth = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -745,15 +819,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
- @"Setting lineWidth to a composite function should update line-width.");
- XCTAssertEqualObjects(layer.lineWidth, functionStyleValue,
- @"lineWidth should round-trip composite functions.");
+ @"Setting lineWidth to a camera-data expression should update line-width.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.lineWidth, pedanticFunctionExpression,
+ @"lineWidth should round-trip camera-data expressions.");
layer.lineWidth = nil;
XCTAssertTrue(rawLayer->getLineWidth().isUndefined(),
@"Unsetting lineWidth should return line-width to the default value.");
- XCTAssertEqualObjects(layer.lineWidth, defaultStyleValue,
+ XCTAssertEqualObjects(layer.lineWidth, defaultExpression,
@"lineWidth should return the default value after being unset.");
// Transition property test
layer.lineWidthTransition = transitionTest;
diff --git a/platform/darwin/test/MGLNSStringAdditionsTests.m b/platform/darwin/test/MGLNSStringAdditionsTests.m
index 03503b7f8a..a3ee7e3433 100644
--- a/platform/darwin/test/MGLNSStringAdditionsTests.m
+++ b/platform/darwin/test/MGLNSStringAdditionsTests.m
@@ -39,4 +39,30 @@
XCTAssertEqualObjects([@"Improve This iPhone" mgl_titleCasedStringWithLocale:locale], @"Improve This iPhone");
}
+- (void)testTransliteratedString {
+ XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Latn"], @"Portland");
+ XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Hans"], @"Portland");
+ XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"Портланд");
+ XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Arab"], @"پُرتلَند");
+ XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Fake"], @"Portland");
+
+ XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Latn"], @"běi jīng");
+ XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Hans"], @"北京");
+ XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"бе̌и йӣнг");
+ XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Arab"], @"بِِ̌ جِينگ");
+ XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Fake"], @"北京");
+
+ XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Latn"], @"Moskva");
+ XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Hans"], @"Mосква");
+ XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"Москва");
+ XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Arab"], @"مُسكڤَ");
+ XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Fake"], @"Mосква");
+
+ XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Latn"], @"rondon");
+ XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Hans"], @"ロンドン");
+ XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"рондон");
+ XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Arab"], @"رُندُن");
+ XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Fake"], @"ロンドン");
+}
+
@end
diff --git a/platform/darwin/test/MGLPredicateTests.mm b/platform/darwin/test/MGLPredicateTests.mm
index 6e6951dcdd..ab4a7e2d88 100644
--- a/platform/darwin/test/MGLPredicateTests.mm
+++ b/platform/darwin/test/MGLPredicateTests.mm
@@ -23,295 +23,9 @@ namespace mbgl {
@implementation MGLPredicateTests
-- (void)testFilterization {
- {
- auto actual = [NSPredicate predicateWithValue:YES].mgl_filter;
- mbgl::style::AllFilter expected;
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithValue:NO].mgl_filter;
- mbgl::style::AnyFilter expected;
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"a = 'b'"].mgl_filter;
- mbgl::style::EqualsFilter expected = { .key = "a", .value = std::string("b") };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"%K = 'Point'", @"$type"].mgl_filter;
- mbgl::style::TypeEqualsFilter expected = { .value = mbgl::FeatureType::Point };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"%K = 67086180", @"$id"].mgl_filter;
- mbgl::style::IdentifierEqualsFilter expected = { .value = UINT64_C(67086180) };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"%K = nil", @"$id"].mgl_filter;
- mbgl::style::NotHasIdentifierFilter expected;
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"a = nil"].mgl_filter;
- mbgl::style::NotHasFilter expected = { .key = "a" };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"%K != 'Point'", @"$type"].mgl_filter;
- mbgl::style::TypeNotEqualsFilter expected = { .value = mbgl::FeatureType::Point };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"%K != 67086180", @"$id"].mgl_filter;
- mbgl::style::IdentifierNotEqualsFilter expected = { .value = UINT64_C(67086180) };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"%K != nil", @"$id"].mgl_filter;
- mbgl::style::HasIdentifierFilter expected;
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"a != 'b'"].mgl_filter;
- mbgl::style::NotEqualsFilter expected = { .key = "a", .value = std::string("b") };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"a != nil"].mgl_filter;
- mbgl::style::HasFilter expected = { .key = "a" };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"a < 'b'"].mgl_filter;
- mbgl::style::LessThanFilter expected = { .key = "a", .value = std::string("b") };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"a <= 'b'"].mgl_filter;
- mbgl::style::LessThanEqualsFilter expected = { .key = "a", .value = std::string("b") };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"a > 'b'"].mgl_filter;
- mbgl::style::GreaterThanFilter expected = { .key = "a", .value = std::string("b") };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"a >= 'b'"].mgl_filter;
- mbgl::style::GreaterThanEqualsFilter expected = { .key = "a", .value = std::string("b") };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"a BETWEEN {'b', 'z'}"].mgl_filter;
- mbgl::style::AllFilter expected = {
- .filters = {
- mbgl::style::GreaterThanEqualsFilter { .key = "a", .value = std::string("b") },
- mbgl::style::LessThanEqualsFilter { .key = "a", .value = std::string("z") },
- },
- };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"a BETWEEN %@", @[@"b", @"z"]].mgl_filter;
- mbgl::style::AllFilter expected = {
- .filters = {
- mbgl::style::GreaterThanEqualsFilter { .key = "a", .value = std::string("b") },
- mbgl::style::LessThanEqualsFilter { .key = "a", .value = std::string("z") },
- },
- };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"a IN {'b', 'c'}"].mgl_filter;
- mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"a IN %@", @[@"b", @"c"]].mgl_filter;
- mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"%K IN {'LineString', 'Polygon'}", @"$type"].mgl_filter;
- mbgl::style::TypeInFilter expected = { .values = { mbgl::FeatureType::LineString, mbgl::FeatureType::Polygon } };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"%K IN %@", @"$type", @[@"LineString", @"Polygon"]].mgl_filter;
- mbgl::style::TypeInFilter expected = { .values = { mbgl::FeatureType::LineString, mbgl::FeatureType::Polygon } };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"%K IN {67086180, 3709678893, 3352016856, 4189833989}", @"$id"].mgl_filter;
- mbgl::style::IdentifierInFilter expected = { .values = { UINT64_C(67086180), UINT64_C(3709678893), UINT64_C(3352016856), UINT64_C(4189833989) } };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"%K IN %@", @"$id", @[@67086180, @3709678893, @3352016856, @4189833989]].mgl_filter;
- mbgl::style::IdentifierInFilter expected = { .values = { UINT64_C(67086180), UINT64_C(3709678893), UINT64_C(3352016856), UINT64_C(4189833989) } };
- MGLAssertEqualFilters(actual, expected);
- }
-
- XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"'Mapbox' IN a"].mgl_filter, NSException, NSInvalidArgumentException);
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"{'b', 'c'} CONTAINS a"].mgl_filter;
- mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"%@ CONTAINS a", @[@"b", @"c"]].mgl_filter;
- mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"%@ CONTAINS %K", @[@"LineString", @"Polygon"], @"$type"].mgl_filter;
- mbgl::style::TypeInFilter expected = { .values = { mbgl::FeatureType::LineString, mbgl::FeatureType::Polygon } };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"{67086180, 3709678893, 3352016856, 4189833989} CONTAINS %K", @"$id"].mgl_filter;
- mbgl::style::IdentifierInFilter expected = { .values = { UINT64_C(67086180), UINT64_C(3709678893), UINT64_C(3352016856), UINT64_C(4189833989) } };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"%@ CONTAINS %K", @[@67086180, @3709678893, @3352016856, @4189833989], @"$id"].mgl_filter;
- mbgl::style::IdentifierInFilter expected = { .values = { UINT64_C(67086180), UINT64_C(3709678893), UINT64_C(3352016856), UINT64_C(4189833989) } };
- MGLAssertEqualFilters(actual, expected);
- }
-
- XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a CONTAINS 'Mapbox'"].mgl_filter, NSException, NSInvalidArgumentException);
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"a == 'b' AND c == 'd'"].mgl_filter;
- mbgl::style::AllFilter expected = {
- .filters = {
- mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") },
- mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") },
- },
- };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"a == 'b' OR c == 'd'"].mgl_filter;
- mbgl::style::AnyFilter expected = {
- .filters = {
- mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") },
- mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") },
- },
- };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"NOT(a == 'b' AND c == 'd')"].mgl_filter;
- mbgl::style::NoneFilter expected = {
- .filters = {
- mbgl::style::AllFilter {
- .filters = {
- mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") },
- mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") },
- },
- },
- },
- };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"NOT(a == 'b' OR c == 'd')"].mgl_filter;
- mbgl::style::NoneFilter expected = {
- .filters = {
- mbgl::style::EqualsFilter { .key = "a", .value = std::string("b") },
- mbgl::style::EqualsFilter { .key = "c", .value = std::string("d") },
- },
- };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"NOT a == nil"].mgl_filter;
- mbgl::style::HasFilter expected = { .key = "a" };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"NOT a != nil"].mgl_filter;
- mbgl::style::NotHasFilter expected = { .key = "a" };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"NOT a IN {'b', 'c'}"].mgl_filter;
- mbgl::style::NotInFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"NOT a IN %@", @[@"b", @"c"]].mgl_filter;
- mbgl::style::NotInFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"NOT {'b', 'c'} CONTAINS a"].mgl_filter;
- mbgl::style::NotInFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
- MGLAssertEqualFilters(actual, expected);
- }
-
- {
- auto actual = [NSPredicate predicateWithFormat:@"NOT %@ CONTAINS a", @[@"b", @"c"]].mgl_filter;
- mbgl::style::NotInFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
- MGLAssertEqualFilters(actual, expected);
- }
-
- XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a BEGINSWITH 'L'"].mgl_filter, NSException, NSInvalidArgumentException);
- XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a ENDSWITH 'itude'"].mgl_filter, NSException, NSInvalidArgumentException);
- XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a LIKE 'glob?trotter'"].mgl_filter, NSException, NSInvalidArgumentException);
- XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a MATCHES 'i\\w{18}n'"].mgl_filter, NSException, NSInvalidArgumentException);
- NSPredicate *selectorPredicate = [NSPredicate predicateWithFormat:@"(SELF isKindOfClass: %@)", [MGLPolyline class]];
- XCTAssertThrowsSpecificNamed(selectorPredicate.mgl_filter, NSException, NSInvalidArgumentException);
-
- XCTAssertThrowsSpecificNamed([NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *, id> * _Nullable bindings) {
- XCTAssertTrue(NO, @"Predicate block should not be evaluated.");
- return NO;
- }].mgl_filter, NSException, NSInvalidArgumentException);
-}
-
- (void)testPredication {
XCTAssertNil([NSPredicate mgl_predicateWithFilter:mbgl::style::NullFilter()]);
-
+
{
mbgl::style::EqualsFilter filter = { .key = "a", .value = std::string("b") };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a = 'b'"]);
@@ -351,12 +65,12 @@ namespace mbgl {
mbgl::style::TypeEqualsFilter filter = { .value = mbgl::FeatureType::Unknown };
XCTAssertThrowsSpecificNamed([NSPredicate mgl_predicateWithFilter:filter], NSException, NSInternalInconsistencyException);
}
-
+
{
mbgl::style::NotHasFilter filter = { .key = "a" };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a = nil"]);
}
-
+
{
mbgl::style::NotEqualsFilter filter = { .key = "a", .value = std::string("b") };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a != 'b'"]);
@@ -379,32 +93,32 @@ namespace mbgl {
NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K != nil", @"$id"];
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected);
}
-
+
{
mbgl::style::HasFilter filter = { .key = "a" };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a != nil"]);
}
-
+
{
mbgl::style::LessThanFilter filter = { .key = "a", .value = std::string("b") };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a < 'b'"]);
}
-
+
{
mbgl::style::LessThanEqualsFilter filter = { .key = "a", .value = std::string("b") };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a <= 'b'"]);
}
-
+
{
mbgl::style::GreaterThanFilter filter = { .key = "a", .value = std::string("b") };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a > 'b'"]);
}
-
+
{
mbgl::style::GreaterThanEqualsFilter filter = { .key = "a", .value = std::string("b") };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a >= 'b'"]);
}
-
+
{
mbgl::style::AllFilter filter = {
.filters = {
@@ -414,7 +128,7 @@ namespace mbgl {
};
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a BETWEEN {'b', 'z'}"]);
}
-
+
{
mbgl::style::AllFilter filter = {
.filters = {
@@ -424,7 +138,7 @@ namespace mbgl {
};
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a BETWEEN {'b', 'z'}"]);
}
-
+
{
mbgl::style::InFilter filter = { .key = "a", .values = { std::string("b"), std::string("c") } };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter].predicateFormat, [NSPredicate predicateWithFormat:@"a IN {'b', 'c'}"].predicateFormat);
@@ -441,7 +155,7 @@ namespace mbgl {
NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K IN {67086180, 3709678893, 3352016856, 4189833989}", @"$id"];
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected);
}
-
+
{
mbgl::style::NotInFilter filter = { .key = "a", .values = { std::string("b"), std::string("c") } };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter].predicateFormat, [NSPredicate predicateWithFormat:@"NOT a IN {'b', 'c'}"].predicateFormat);
@@ -458,12 +172,12 @@ namespace mbgl {
NSPredicate *expected = [NSPredicate predicateWithFormat:@"NOT %K IN {67086180, 3709678893, 3352016856, 4189833989}", @"$id"];
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected);
}
-
+
{
mbgl::style::AllFilter filter;
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithValue:YES]);
}
-
+
{
mbgl::style::AllFilter filter = {
.filters = {
@@ -473,12 +187,12 @@ namespace mbgl {
};
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a == 'b' AND c == 'd'"]);
}
-
+
{
mbgl::style::AnyFilter filter;
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithValue:NO]);
}
-
+
{
mbgl::style::AnyFilter filter = {
.filters = {
@@ -488,12 +202,12 @@ namespace mbgl {
};
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a == 'b' OR c == 'd'"]);
}
-
+
{
mbgl::style::NoneFilter filter;
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithValue:YES]);
}
-
+
{
mbgl::style::NoneFilter filter = {
.filters = {
@@ -505,69 +219,339 @@ namespace mbgl {
}
}
-- (void)testSymmetry {
- [self testSymmetryWithFormat:@"a = 1" reverseFormat:@"1 = a" mustRoundTrip:YES];
- [self testSymmetryWithFormat:@"a != 1" reverseFormat:@"1 != a" mustRoundTrip:YES];
- XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a = b"].mgl_filter, NSException, NSInvalidArgumentException);
- XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"1 = 1"].mgl_filter, NSException, NSInvalidArgumentException);
-
- // In the predicate format language, $ is a special character denoting a
- // variable. Use %K to escape the special feature attribute $id.
- XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"$id == 670861802"].mgl_filter, NSException, NSInvalidArgumentException);
- XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a = $id"].mgl_filter, NSException, NSInvalidArgumentException);
-
- [self testSymmetryWithFormat:@"a = nil" reverseFormat:@"nil = a" mustRoundTrip:YES];
- [self testSymmetryWithFormat:@"a != nil" reverseFormat:@"nil != a" mustRoundTrip:YES];
-
- [self testSymmetryWithFormat:@"a < 1" reverseFormat:@"1 > a" mustRoundTrip:YES];
- [self testSymmetryWithFormat:@"a <= 1" reverseFormat:@"1 >= a" mustRoundTrip:YES];
- [self testSymmetryWithFormat:@"a > 1" reverseFormat:@"1 < a" mustRoundTrip:YES];
- [self testSymmetryWithFormat:@"a >= 1" reverseFormat:@"1 <= a" mustRoundTrip:YES];
-
- [self testSymmetryWithFormat:@"a BETWEEN {1, 2}" reverseFormat:@"1 <= a && 2 >= a" mustRoundTrip:YES];
- [self testSymmetryWithPredicate:[NSPredicate predicateWithFormat:@"a BETWEEN %@", @[@1, @2]]
- reversePredicate:[NSPredicate predicateWithFormat:@"1 <= a && 2 >= a"]
- mustRoundTrip:YES];
- XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"{1, 2} BETWEEN a"].mgl_filter, NSException, NSInvalidArgumentException);
- NSPredicate *betweenSetPredicate = [NSPredicate predicateWithFormat:@"a BETWEEN %@", [NSSet setWithObjects:@1, @2, nil]];
- XCTAssertThrowsSpecificNamed(betweenSetPredicate.mgl_filter, NSException, NSInvalidArgumentException);
- XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a BETWEEN {1}"].mgl_filter, NSException, NSInvalidArgumentException);
- XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a BETWEEN {1, 2, 3}"].mgl_filter, NSException, NSInvalidArgumentException);
-
- [self testSymmetryWithFormat:@"a IN {1, 2}" reverseFormat:@"{1, 2} CONTAINS a" mustRoundTrip:NO];
- [self testSymmetryWithPredicate:[NSPredicate predicateWithFormat:@"a IN %@", @[@1, @2]]
- reversePredicate:[NSPredicate predicateWithFormat:@"%@ CONTAINS a", @[@1, @2]]
- mustRoundTrip:YES];
+- (void)testUnsupportedFilterPredicates {
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"1 == 2"].mgl_filter, NSException, NSInvalidArgumentException);
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"1 == 1"].mgl_filter, NSException, NSInvalidArgumentException);
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithValue:YES].mgl_filter, NSException, NSInvalidArgumentException);
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithValue:NO].mgl_filter, NSException, NSInvalidArgumentException);
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a BEGINSWITH 'L'"].mgl_filter, NSException, NSInvalidArgumentException);
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a ENDSWITH 'itude'"].mgl_filter, NSException, NSInvalidArgumentException);
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a LIKE 'glob?trotter'"].mgl_filter, NSException, NSInvalidArgumentException);
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a MATCHES 'i\\w{18}n'"].mgl_filter, NSException, NSInvalidArgumentException);
+ NSPredicate *selectorPredicate = [NSPredicate predicateWithFormat:@"(SELF isKindOfClass: %@)", [MGLPolyline class]];
+ XCTAssertThrowsSpecificNamed(selectorPredicate.mgl_filter, NSException, NSInvalidArgumentException);
+
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *, id> * _Nullable bindings) {
+ XCTAssertTrue(NO, @"Predicate block should not be evaluated.");
+ return NO;
+ }].mgl_filter, NSException, NSInvalidArgumentException);
+}
- // The reverse formats here are a bit backwards because we canonicalize
- // a reverse CONTAINS to a forward IN.
- [self testSymmetryWithFormat:@"{1, 2} CONTAINS a" reverseFormat:@"{1, 2} CONTAINS a" mustRoundTrip:NO];
- [self testSymmetryWithPredicate:[NSPredicate predicateWithFormat:@"%@ CONTAINS a", @[@1, @2]]
- reversePredicate:[NSPredicate predicateWithFormat:@"%@ CONTAINS a", @[@1, @2]]
- mustRoundTrip:NO];
+- (void)testComparisonPredicates {
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"x == YES"];
+ NSArray *jsonExpression = @[@"==", @[@"get", @"x"], @YES];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:jsonExpression], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:jsonExpression]
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"CAST(x, 'NSNumber') < 5"];
+ NSArray *jsonExpression = @[@"<", @[@"to-number", @[@"get", @"x"]], @5];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:jsonExpression], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:jsonExpression]
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"CAST(x, 'NSNumber') > 5"];
+ NSArray *jsonExpression = @[@">", @[@"to-number", @[@"get", @"x"]], @5];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:jsonExpression], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:jsonExpression]
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"CAST(x, 'NSNumber') <= 5"];
+ NSArray *jsonExpression = @[@"<=", @[@"to-number", @[@"get", @"x"]], @5];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:jsonExpression], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:jsonExpression]
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"CAST(x, 'NSNumber') >= 5"];
+ NSArray *jsonExpression = @[@">=", @[@"to-number", @[@"get", @"x"]], @5];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:jsonExpression], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:jsonExpression]
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"CAST(x, 'NSString') > 'value'"];
+ NSArray *jsonExpression = @[@">", @[@"to-string", @[@"get", @"x"]], @"value"];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:jsonExpression], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:jsonExpression]
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"a = 'b'"];
+ NSArray *jsonExpression = @[@"==", @[@"get", @"a"], @"b"];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ [self testSymmetryWithPredicate:predicate
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"$geometryType = 'Point'"];
+ NSArray *jsonExpression = @[@"==", @[@"geometry-type"], @"Point"];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ [self testSymmetryWithPredicate:predicate
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"$featureIdentifier = 67086180"];
+ NSArray *jsonExpression = @[@"==", @[@"id"], @67086180];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ [self testSymmetryWithPredicate:predicate
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"$featureIdentifier = nil"];
+ NSArray *jsonExpression = @[@"==", @[@"id"], [NSNull null]];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ [self testSymmetryWithPredicate:predicate
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"a = nil"];
+ NSArray *jsonExpression = @[@"==", @[@"get", @"a"], [NSNull null]];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ [self testSymmetryWithPredicate:predicate
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"$geometryType != 'Point'"];
+ NSArray *jsonExpression = @[@"!=", @[@"geometry-type"], @"Point"];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ [self testSymmetryWithPredicate:predicate
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"$featureIdentifier != 67086180"];
+ NSArray *jsonExpression = @[@"!=", @[@"id"], @67086180];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ [self testSymmetryWithPredicate:predicate
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"$featureIdentifier != nil"];
+ NSArray *jsonExpression = @[@"!=", @[@"id"], [NSNull null]];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ [self testSymmetryWithPredicate:predicate
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"a != 'b'"];
+ NSArray *jsonExpression = @[@"!=", @[@"get", @"a"], @"b"];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ [self testSymmetryWithPredicate:predicate
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"a != nil"];
+ NSArray *jsonExpression = @[@"!=", @[@"get", @"a"], [NSNull null]];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ [self testSymmetryWithPredicate:predicate
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"CAST(a, 'NSString') < 'b'"];
+ NSArray *jsonExpression = @[@"<", @[@"to-string", @[@"get", @"a"]], @"b"];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:jsonExpression], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:jsonExpression]
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"CAST(a, 'NSString') <= 'b'"];
+ NSArray *jsonExpression = @[@"<=", @[@"to-string", @[@"get", @"a"]], @"b"];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:jsonExpression], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:jsonExpression]
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"CAST(a, 'NSString') > 'b'"];
+ NSArray *jsonExpression = @[@">", @[@"to-string", @[@"get", @"a"]], @"b"];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:jsonExpression], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:jsonExpression]
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"CAST(a, 'NSString') >= 'b'"];
+ NSArray *jsonExpression = @[@">=", @[@"to-string", @[@"get", @"a"]], @"b"];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:jsonExpression], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:jsonExpression]
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"CAST(a, 'NSString') BETWEEN {'b', 'z'}"];
+ NSArray *jsonExpression =@[@"all", @[@"<=", @"b", @[@"to-string", @[@"get", @"a"]]], @[@"<=", @[@"to-string", @[@"get", @"a"]], @"z"]];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:jsonExpression], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:jsonExpression]
+ mustRoundTrip:NO];
+ }
+ {
+ NSExpression *limits = [NSExpression expressionForAggregate:@[[NSExpression expressionForConstantValue:@10], [NSExpression expressionForConstantValue:@100]]];
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"CAST(x, 'NSNumber') BETWEEN %@", limits];
+ NSArray *jsonExpression = @[@"all", @[@">=", @[@"to-number", @[@"get", @"x"]], @10], @[@"<=", @[@"to-number", @[@"get", @"x"]], @100]];
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:jsonExpression], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:jsonExpression]
+ mustRoundTrip:NO];
+ }
+ {
+ NSArray *expected = @[@"all", @[@"<=", @10, @[@"to-number", @[@"get", @"x"]]], @[@"<=", @[@"to-number", @[@"get", @"x"]], @100]];
+ NSExpression *limits = [NSExpression expressionForAggregate:@[[NSExpression expressionForConstantValue:@10], [NSExpression expressionForConstantValue:@100]]];
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"CAST(x, 'NSNumber') BETWEEN %@", limits];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:expected], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:expected]
+ mustRoundTrip:NO];
+ }
+ {
+ NSArray *expected = @[@"all", @[@"<=", @10, @[@"to-number", @[@"get", @"x"]]], @[@">=", @100, @[@"to-number", @[@"get", @"x"]]]];
+ NSExpression *limits = [NSExpression expressionForAggregate:@[[NSExpression expressionForConstantValue:@10], [NSExpression expressionForConstantValue:@100]]];
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"CAST(x, 'NSNumber') BETWEEN %@", limits];
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:expected], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:expected]
+ mustRoundTrip:NO];
+ }
+ {
+ NSArray *expected = @[@"all", @[@">=", @[@"to-number", @[@"get", @"x"]], @10], @[@">=", @100, @[@"to-number", @[@"get", @"x"]]]];
+ NSExpression *limits = [NSExpression expressionForAggregate:@[[NSExpression expressionForConstantValue:@10], [NSExpression expressionForConstantValue:@100]]];
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"CAST(x, 'NSNumber') BETWEEN %@", limits];
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:expected], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:expected]
+ mustRoundTrip:NO];
+ }
+ {
+ NSArray *expected = @[@"match", @[@"id"], @6, @YES, @5, @YES, @4, @YES, @3, @YES, @NO];
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"$featureIdentifier IN { 6, 5, 4, 3}"];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
+ NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH(CAST($featureIdentifier, 'NSNumber'), 3, YES, 4, YES, 5, YES, 6, YES, NO) == YES"];
+ auto forwardFilter = [NSPredicate mgl_predicateWithJSONObject:expected].mgl_filter;
+ NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter];
+ XCTAssertEqualObjects(predicateAfter, forwardPredicateAfter);
+ }
+ {
+ NSArray *expected = @[@"!", @[@"match", @[@"get", @"x"], @6, @YES, @5, @YES, @4, @YES, @3, @YES, @NO]];
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT x IN { 6, 5, 4, 3}"];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
+ NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"NOT MGL_MATCH(CAST(x, 'NSNumber'), 3, YES, 4, YES, 5, YES, 6, YES, NO) == YES"];
+ auto forwardFilter = [NSPredicate mgl_predicateWithJSONObject:expected].mgl_filter;
+ NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter];
+ XCTAssertEqualObjects(predicateAfter, forwardPredicateAfter);
+ }
+ {
+ NSArray *expected = @[@"match", @[@"get", @"a"], @"b", @YES, @"c", @YES, @NO];
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"a IN { 'b', 'c' }"];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
+ NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH(CAST(a, 'NSString'), 'b', YES, 'c', YES, NO) == YES"];
+ auto forwardFilter = [NSPredicate mgl_predicateWithJSONObject:expected].mgl_filter;
+ NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter];
+ XCTAssertEqualObjects(predicateAfter, forwardPredicateAfter);
+ }
+ {
+ NSArray *expected = @[@"match", @[@"geometry-type"], @"LineString", @YES, @"Polygon", @YES, @NO];
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%@ IN %@", [NSExpression expressionForVariable:@"geometryType"], @[@"LineString", @"Polygon"]];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
+ NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH($geometryType, 'LineString', YES, 'Polygon', YES, NO) == YES"];
+ auto forwardFilter = [NSPredicate mgl_predicateWithJSONObject:expected].mgl_filter;
+ NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter];
+ XCTAssertEqualObjects(predicateAfter, forwardPredicateAfter);
+ }
+ {
+ NSArray *expected = @[@"match", @[@"get", @"x"], @6, @YES, @5, @YES, @4, @YES, @3, @YES, @NO];
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"{ 6, 5, 4, 3} CONTAINS x"];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
+ NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH(CAST(x, 'NSNumber'), 3, YES, 4, YES, 5, YES, 6, YES, NO) == YES"];
+ auto forwardFilter = [NSPredicate mgl_predicateWithJSONObject:expected].mgl_filter;
+ NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter];
+ XCTAssertEqualObjects(predicateAfter, forwardPredicateAfter);
+ }
+ {
+ NSArray *expected = @[@"match", @[@"geometry-type"], @"LineString", @YES, @"Polygon", @YES, @NO];
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%@ CONTAINS %@", @[@"LineString", @"Polygon"], [NSExpression expressionForVariable:@"geometryType"]];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
+ NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH($geometryType, 'LineString', YES, 'Polygon', YES, NO) == YES"];
+ auto forwardFilter = [NSPredicate mgl_predicateWithJSONObject:expected].mgl_filter;
+ NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter];
+ XCTAssertEqualObjects(predicateAfter, forwardPredicateAfter);
+ }
+ {
+ NSArray *expected = @[@"match", @[@"id"], @6, @YES, @5, @YES, @4, @YES, @3, @YES, @NO];
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"{ 6, 5, 4, 3} CONTAINS $featureIdentifier"];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
+ NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH(CAST($featureIdentifier, 'NSNumber'), 3, YES, 4, YES, 5, YES, 6, YES, NO) == YES"];
+ auto forwardFilter = [NSPredicate mgl_predicateWithJSONObject:expected].mgl_filter;
+ NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter];
+ XCTAssertEqualObjects(predicateAfter, forwardPredicateAfter);
+ }
}
-- (void)testSymmetryWithFormat:(NSString *)forwardFormat reverseFormat:(NSString *)reverseFormat mustRoundTrip:(BOOL)mustRoundTrip {
- NSPredicate *forwardPredicate = [NSPredicate predicateWithFormat:forwardFormat];
- NSPredicate *reversePredicate = reverseFormat ? [NSPredicate predicateWithFormat:reverseFormat] : nil;
- [self testSymmetryWithPredicate:forwardPredicate reversePredicate:reversePredicate mustRoundTrip:mustRoundTrip];
+- (void)testCompoundPredicates {
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"a == 'b' AND c == 'd'"];
+ NSArray *jsonExpression = @[@"all", @[@"==", @[@"get", @"a"], @"b"], @[@"==", @[@"get", @"c"], @"d"]];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:jsonExpression], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:jsonExpression]
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"a == 'b' OR c == 'd'"];
+ NSArray *jsonExpression = @[@"any", @[@"==", @[@"get", @"a"], @"b"], @[@"==", @[@"get", @"c"], @"d"]];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:jsonExpression], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:jsonExpression]
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT(a == 'b' AND c == 'd')"];
+ NSArray *jsonExpression = @[@"!", @[@"all", @[@"==", @[@"get", @"a"], @"b"], @[@"==", @[@"get", @"c"], @"d"]]];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:jsonExpression], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:jsonExpression]
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT(a == 'b' OR c == 'd')"];
+ NSArray *jsonExpression = @[@"!", @[@"any", @[@"==", @[@"get", @"a"], @"b"], @[@"==", @[@"get", @"c"], @"d"]]];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:jsonExpression], predicate);
+ [self testSymmetryWithPredicate:[NSPredicate mgl_predicateWithJSONObject:jsonExpression]
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT a == nil"];
+ NSArray *jsonExpression = @[@"!", @[@"==", @[@"get", @"a"], [NSNull null]]];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ [self testSymmetryWithPredicate:predicate
+ mustRoundTrip:NO];
+ }
+ {
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT a != nil"];
+ NSArray *jsonExpression = @[@"!", @[@"!=", @[@"get", @"a"], [NSNull null]]];
+ XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, jsonExpression);
+ [self testSymmetryWithPredicate:predicate
+ mustRoundTrip:NO];
+ }
}
-- (void)testSymmetryWithPredicate:(NSPredicate *)forwardPredicate reversePredicate:(NSPredicate *)reversePredicate mustRoundTrip:(BOOL)mustRoundTrip {
+- (void)testSymmetryWithPredicate:(NSPredicate *)forwardPredicate mustRoundTrip:(BOOL)mustRoundTrip {
auto forwardFilter = forwardPredicate.mgl_filter;
NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter];
if (mustRoundTrip) {
// A collection of ints may turn into an aggregate of longs, for
// example, so compare formats instead of the predicates themselves.
XCTAssertEqualObjects(forwardPredicate.predicateFormat, forwardPredicateAfter.predicateFormat);
- }
-
- if (reversePredicate) {
- auto reverseFilter = reversePredicate.mgl_filter;
- NSPredicate *reversePredicateAfter = [NSPredicate mgl_predicateWithFilter:reverseFilter];
- XCTAssertNotEqualObjects(reversePredicate, reversePredicateAfter);
-
- XCTAssertEqualObjects(forwardPredicateAfter, reversePredicateAfter);
+ } else {
+ XCTAssertEqualObjects(forwardPredicate, forwardPredicateAfter);
}
}
diff --git a/platform/darwin/test/MGLRasterStyleLayerTests.mm b/platform/darwin/test/MGLRasterStyleLayerTests.mm
index 7b0757eeb6..c8e454743e 100644
--- a/platform/darwin/test/MGLRasterStyleLayerTests.mm
+++ b/platform/darwin/test/MGLRasterStyleLayerTests.mm
@@ -34,117 +34,132 @@
{
XCTAssertTrue(rawLayer->getRasterBrightnessMax().isUndefined(),
@"raster-brightness-max should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.maximumRasterBrightness;
+ NSExpression *defaultExpression = layer.maximumRasterBrightness;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.maximumRasterBrightness = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.maximumRasterBrightness = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getRasterBrightnessMax(), propertyValue,
- @"Setting maximumRasterBrightness to a constant value should update raster-brightness-max.");
- XCTAssertEqualObjects(layer.maximumRasterBrightness, constantStyleValue,
- @"maximumRasterBrightness should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.maximumRasterBrightness = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting maximumRasterBrightness to a constant value expression should update raster-brightness-max.");
+ XCTAssertEqualObjects(layer.maximumRasterBrightness, constantExpression,
+ @"maximumRasterBrightness should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.maximumRasterBrightness = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getRasterBrightnessMax(), propertyValue,
- @"Setting maximumRasterBrightness to a camera function should update raster-brightness-max.");
- XCTAssertEqualObjects(layer.maximumRasterBrightness, functionStyleValue,
- @"maximumRasterBrightness should round-trip camera functions.");
+ @"Setting maximumRasterBrightness to a camera expression should update raster-brightness-max.");
+ XCTAssertEqualObjects(layer.maximumRasterBrightness, functionExpression,
+ @"maximumRasterBrightness should round-trip camera expressions.");
layer.maximumRasterBrightness = nil;
XCTAssertTrue(rawLayer->getRasterBrightnessMax().isUndefined(),
@"Unsetting maximumRasterBrightness should return raster-brightness-max to the default value.");
- XCTAssertEqualObjects(layer.maximumRasterBrightness, defaultStyleValue,
+ XCTAssertEqualObjects(layer.maximumRasterBrightness, defaultExpression,
@"maximumRasterBrightness should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.maximumRasterBrightness = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.maximumRasterBrightness = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.maximumRasterBrightness = functionExpression, NSException, NSInvalidArgumentException, @"MGLRasterLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.maximumRasterBrightness = functionExpression, NSException, NSInvalidArgumentException, @"MGLRasterLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// raster-brightness-min
{
XCTAssertTrue(rawLayer->getRasterBrightnessMin().isUndefined(),
@"raster-brightness-min should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.minimumRasterBrightness;
+ NSExpression *defaultExpression = layer.minimumRasterBrightness;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.minimumRasterBrightness = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.minimumRasterBrightness = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getRasterBrightnessMin(), propertyValue,
- @"Setting minimumRasterBrightness to a constant value should update raster-brightness-min.");
- XCTAssertEqualObjects(layer.minimumRasterBrightness, constantStyleValue,
- @"minimumRasterBrightness should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.minimumRasterBrightness = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting minimumRasterBrightness to a constant value expression should update raster-brightness-min.");
+ XCTAssertEqualObjects(layer.minimumRasterBrightness, constantExpression,
+ @"minimumRasterBrightness should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.minimumRasterBrightness = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getRasterBrightnessMin(), propertyValue,
- @"Setting minimumRasterBrightness to a camera function should update raster-brightness-min.");
- XCTAssertEqualObjects(layer.minimumRasterBrightness, functionStyleValue,
- @"minimumRasterBrightness should round-trip camera functions.");
+ @"Setting minimumRasterBrightness to a camera expression should update raster-brightness-min.");
+ XCTAssertEqualObjects(layer.minimumRasterBrightness, functionExpression,
+ @"minimumRasterBrightness should round-trip camera expressions.");
layer.minimumRasterBrightness = nil;
XCTAssertTrue(rawLayer->getRasterBrightnessMin().isUndefined(),
@"Unsetting minimumRasterBrightness should return raster-brightness-min to the default value.");
- XCTAssertEqualObjects(layer.minimumRasterBrightness, defaultStyleValue,
+ XCTAssertEqualObjects(layer.minimumRasterBrightness, defaultExpression,
@"minimumRasterBrightness should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.minimumRasterBrightness = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.minimumRasterBrightness = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.minimumRasterBrightness = functionExpression, NSException, NSInvalidArgumentException, @"MGLRasterLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.minimumRasterBrightness = functionExpression, NSException, NSInvalidArgumentException, @"MGLRasterLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// raster-contrast
{
XCTAssertTrue(rawLayer->getRasterContrast().isUndefined(),
@"raster-contrast should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterContrast;
+ NSExpression *defaultExpression = layer.rasterContrast;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.rasterContrast = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.rasterContrast = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getRasterContrast(), propertyValue,
- @"Setting rasterContrast to a constant value should update raster-contrast.");
- XCTAssertEqualObjects(layer.rasterContrast, constantStyleValue,
- @"rasterContrast should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.rasterContrast = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting rasterContrast to a constant value expression should update raster-contrast.");
+ XCTAssertEqualObjects(layer.rasterContrast, constantExpression,
+ @"rasterContrast should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.rasterContrast = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getRasterContrast(), propertyValue,
- @"Setting rasterContrast to a camera function should update raster-contrast.");
- XCTAssertEqualObjects(layer.rasterContrast, functionStyleValue,
- @"rasterContrast should round-trip camera functions.");
+ @"Setting rasterContrast to a camera expression should update raster-contrast.");
+ XCTAssertEqualObjects(layer.rasterContrast, functionExpression,
+ @"rasterContrast should round-trip camera expressions.");
layer.rasterContrast = nil;
XCTAssertTrue(rawLayer->getRasterContrast().isUndefined(),
@"Unsetting rasterContrast should return raster-contrast to the default value.");
- XCTAssertEqualObjects(layer.rasterContrast, defaultStyleValue,
+ XCTAssertEqualObjects(layer.rasterContrast, defaultExpression,
@"rasterContrast should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.rasterContrast = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.rasterContrast = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.rasterContrast = functionExpression, NSException, NSInvalidArgumentException, @"MGLRasterLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.rasterContrast = functionExpression, NSException, NSInvalidArgumentException, @"MGLRasterLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
// Transition property test
layer.rasterContrastTransition = transitionTest;
auto toptions = rawLayer->getRasterContrastTransition();
@@ -160,126 +175,132 @@
{
XCTAssertTrue(rawLayer->getRasterFadeDuration().isUndefined(),
@"raster-fade-duration should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterFadeDuration;
+ NSExpression *defaultExpression = layer.rasterFadeDuration;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.rasterFadeDuration = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.rasterFadeDuration = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getRasterFadeDuration(), propertyValue,
- @"Setting rasterFadeDuration to a constant value should update raster-fade-duration.");
- XCTAssertEqualObjects(layer.rasterFadeDuration, constantStyleValue,
- @"rasterFadeDuration should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.rasterFadeDuration = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting rasterFadeDuration to a constant value expression should update raster-fade-duration.");
+ XCTAssertEqualObjects(layer.rasterFadeDuration, constantExpression,
+ @"rasterFadeDuration should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.rasterFadeDuration = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getRasterFadeDuration(), propertyValue,
- @"Setting rasterFadeDuration to a camera function should update raster-fade-duration.");
- XCTAssertEqualObjects(layer.rasterFadeDuration, functionStyleValue,
- @"rasterFadeDuration should round-trip camera functions.");
+ @"Setting rasterFadeDuration to a camera expression should update raster-fade-duration.");
+ XCTAssertEqualObjects(layer.rasterFadeDuration, functionExpression,
+ @"rasterFadeDuration should round-trip camera expressions.");
layer.rasterFadeDuration = nil;
XCTAssertTrue(rawLayer->getRasterFadeDuration().isUndefined(),
@"Unsetting rasterFadeDuration should return raster-fade-duration to the default value.");
- XCTAssertEqualObjects(layer.rasterFadeDuration, defaultStyleValue,
+ XCTAssertEqualObjects(layer.rasterFadeDuration, defaultExpression,
@"rasterFadeDuration should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.rasterFadeDuration = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.rasterFadeDuration = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- // Transition property test
- layer.rasterFadeDurationTransition = transitionTest;
- auto toptions = rawLayer->getRasterFadeDurationTransition();
- XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay);
- XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration);
-
- MGLTransition rasterFadeDurationTransition = layer.rasterFadeDurationTransition;
- XCTAssertEqual(rasterFadeDurationTransition.delay, transitionTest.delay);
- XCTAssertEqual(rasterFadeDurationTransition.duration, transitionTest.duration);
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.rasterFadeDuration = functionExpression, NSException, NSInvalidArgumentException, @"MGLRasterLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.rasterFadeDuration = functionExpression, NSException, NSInvalidArgumentException, @"MGLRasterLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// raster-hue-rotate
{
XCTAssertTrue(rawLayer->getRasterHueRotate().isUndefined(),
@"raster-hue-rotate should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterHueRotation;
+ NSExpression *defaultExpression = layer.rasterHueRotation;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.rasterHueRotation = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.rasterHueRotation = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getRasterHueRotate(), propertyValue,
- @"Setting rasterHueRotation to a constant value should update raster-hue-rotate.");
- XCTAssertEqualObjects(layer.rasterHueRotation, constantStyleValue,
- @"rasterHueRotation should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.rasterHueRotation = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting rasterHueRotation to a constant value expression should update raster-hue-rotate.");
+ XCTAssertEqualObjects(layer.rasterHueRotation, constantExpression,
+ @"rasterHueRotation should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.rasterHueRotation = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getRasterHueRotate(), propertyValue,
- @"Setting rasterHueRotation to a camera function should update raster-hue-rotate.");
- XCTAssertEqualObjects(layer.rasterHueRotation, functionStyleValue,
- @"rasterHueRotation should round-trip camera functions.");
+ @"Setting rasterHueRotation to a camera expression should update raster-hue-rotate.");
+ XCTAssertEqualObjects(layer.rasterHueRotation, functionExpression,
+ @"rasterHueRotation should round-trip camera expressions.");
layer.rasterHueRotation = nil;
XCTAssertTrue(rawLayer->getRasterHueRotate().isUndefined(),
@"Unsetting rasterHueRotation should return raster-hue-rotate to the default value.");
- XCTAssertEqualObjects(layer.rasterHueRotation, defaultStyleValue,
+ XCTAssertEqualObjects(layer.rasterHueRotation, defaultExpression,
@"rasterHueRotation should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.rasterHueRotation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.rasterHueRotation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.rasterHueRotation = functionExpression, NSException, NSInvalidArgumentException, @"MGLRasterLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.rasterHueRotation = functionExpression, NSException, NSInvalidArgumentException, @"MGLRasterLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// raster-opacity
{
XCTAssertTrue(rawLayer->getRasterOpacity().isUndefined(),
@"raster-opacity should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterOpacity;
+ NSExpression *defaultExpression = layer.rasterOpacity;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.rasterOpacity = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.rasterOpacity = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getRasterOpacity(), propertyValue,
- @"Setting rasterOpacity to a constant value should update raster-opacity.");
- XCTAssertEqualObjects(layer.rasterOpacity, constantStyleValue,
- @"rasterOpacity should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.rasterOpacity = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting rasterOpacity to a constant value expression should update raster-opacity.");
+ XCTAssertEqualObjects(layer.rasterOpacity, constantExpression,
+ @"rasterOpacity should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.rasterOpacity = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getRasterOpacity(), propertyValue,
- @"Setting rasterOpacity to a camera function should update raster-opacity.");
- XCTAssertEqualObjects(layer.rasterOpacity, functionStyleValue,
- @"rasterOpacity should round-trip camera functions.");
+ @"Setting rasterOpacity to a camera expression should update raster-opacity.");
+ XCTAssertEqualObjects(layer.rasterOpacity, functionExpression,
+ @"rasterOpacity should round-trip camera expressions.");
layer.rasterOpacity = nil;
XCTAssertTrue(rawLayer->getRasterOpacity().isUndefined(),
@"Unsetting rasterOpacity should return raster-opacity to the default value.");
- XCTAssertEqualObjects(layer.rasterOpacity, defaultStyleValue,
+ XCTAssertEqualObjects(layer.rasterOpacity, defaultExpression,
@"rasterOpacity should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.rasterOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.rasterOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.rasterOpacity = functionExpression, NSException, NSInvalidArgumentException, @"MGLRasterLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.rasterOpacity = functionExpression, NSException, NSInvalidArgumentException, @"MGLRasterLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
// Transition property test
layer.rasterOpacityTransition = transitionTest;
auto toptions = rawLayer->getRasterOpacityTransition();
@@ -295,39 +316,44 @@
{
XCTAssertTrue(rawLayer->getRasterSaturation().isUndefined(),
@"raster-saturation should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterSaturation;
+ NSExpression *defaultExpression = layer.rasterSaturation;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.rasterSaturation = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.rasterSaturation = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getRasterSaturation(), propertyValue,
- @"Setting rasterSaturation to a constant value should update raster-saturation.");
- XCTAssertEqualObjects(layer.rasterSaturation, constantStyleValue,
- @"rasterSaturation should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.rasterSaturation = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting rasterSaturation to a constant value expression should update raster-saturation.");
+ XCTAssertEqualObjects(layer.rasterSaturation, constantExpression,
+ @"rasterSaturation should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.rasterSaturation = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getRasterSaturation(), propertyValue,
- @"Setting rasterSaturation to a camera function should update raster-saturation.");
- XCTAssertEqualObjects(layer.rasterSaturation, functionStyleValue,
- @"rasterSaturation should round-trip camera functions.");
+ @"Setting rasterSaturation to a camera expression should update raster-saturation.");
+ XCTAssertEqualObjects(layer.rasterSaturation, functionExpression,
+ @"rasterSaturation should round-trip camera expressions.");
layer.rasterSaturation = nil;
XCTAssertTrue(rawLayer->getRasterSaturation().isUndefined(),
@"Unsetting rasterSaturation should return raster-saturation to the default value.");
- XCTAssertEqualObjects(layer.rasterSaturation, defaultStyleValue,
+ XCTAssertEqualObjects(layer.rasterSaturation, defaultExpression,
@"rasterSaturation should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.rasterSaturation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.rasterSaturation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.rasterSaturation = functionExpression, NSException, NSInvalidArgumentException, @"MGLRasterLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.rasterSaturation = functionExpression, NSException, NSInvalidArgumentException, @"MGLRasterLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
// Transition property test
layer.rasterSaturationTransition = transitionTest;
auto toptions = rawLayer->getRasterSaturationTransition();
diff --git a/platform/darwin/test/MGLSDKTestHelpers.swift b/platform/darwin/test/MGLSDKTestHelpers.swift
index f21041782e..727d8bf0c6 100644
--- a/platform/darwin/test/MGLSDKTestHelpers.swift
+++ b/platform/darwin/test/MGLSDKTestHelpers.swift
@@ -1,3 +1,4 @@
+import XCTest
import Foundation
class MGLSDKTestHelpers {
@@ -22,9 +23,9 @@ extension MGLSDKTestHelpers {
class func protocolMethodDescriptions(_ p: Protocol) -> Set<String> {
var methods = Set<String>()
var methodCount = UInt32()
- let methodDescriptionList: UnsafeMutablePointer<objc_method_description>! = protocol_copyMethodDescriptionList(p, false, true, &methodCount)
+ let methodDescriptionList = protocol_copyMethodDescriptionList(p, false, true, &methodCount)
for i in 0..<Int(methodCount) {
- let description: objc_method_description = methodDescriptionList[i]
+ let description = methodDescriptionList![i]
XCTAssertNotNil(description.name?.description)
methods.insert(description.name!.description)
}
@@ -35,11 +36,16 @@ extension MGLSDKTestHelpers {
class func classMethodDescriptions(_ cls: Swift.AnyClass) -> Set<String> {
var methods = Set<String>()
var methodCount = UInt32()
- let methodList: UnsafeMutablePointer<Method?>! = class_copyMethodList(cls, &methodCount)
+ let methodList = class_copyMethodList(cls, &methodCount)
for i in 0..<Int(methodCount) {
- let method = methodList[i]
- let selector : Selector = method_getName(method)
- methods.insert(selector.description)
+ let method = methodList![i]
+ let selector = method_getName(method)
+ #if os(macOS)
+ methods.insert(selector.description)
+ #else
+ XCTAssertNotNil(selector)
+ methods.insert(selector!.description)
+ #endif
}
free(methodList)
return methods
diff --git a/platform/darwin/test/MGLShapeSourceTests.mm b/platform/darwin/test/MGLShapeSourceTests.mm
index 561af7f3d0..d3f9a599e2 100644
--- a/platform/darwin/test/MGLShapeSourceTests.mm
+++ b/platform/darwin/test/MGLShapeSourceTests.mm
@@ -297,7 +297,10 @@
// when a shape is included in the features array
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:sizeof(coordinates)/sizeof(coordinates[0]) interiorPolygons:nil];
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wobjc-literal-conversion"
XCTAssertThrowsSpecificNamed([[MGLShapeSource alloc] initWithIdentifier:@"source-id-invalid" features:@[polygon] options:nil], NSException, NSInvalidArgumentException, @"Shape source should raise an exception if a shape is sent to the features initializer");
+#pragma clang diagnostic pop
}
- (void)testMGLShapeSourceWithShapesConvenienceInitializer {
diff --git a/platform/darwin/test/MGLSourceQueryTests.m b/platform/darwin/test/MGLSourceQueryTests.m
index d1ef180a52..b321da1ea4 100644
--- a/platform/darwin/test/MGLSourceQueryTests.m
+++ b/platform/darwin/test/MGLSourceQueryTests.m
@@ -7,8 +7,8 @@
@implementation MGLSourceQueryTests
-- (void) testQueryVectorSource {
- MGLVectorSource *source = [[MGLVectorSource alloc] initWithIdentifier:@"vector" tileURLTemplates:@[@"fake"] options:nil];
+- (void) testQueryVectorTileSource {
+ MGLVectorTileSource *source = [[MGLVectorTileSource alloc] initWithIdentifier:@"vector" tileURLTemplates:@[@"fake"] options:nil];
NSSet *sourceLayers = [NSSet setWithObjects:@"buildings", @"water", nil];
NSArray* features = [source featuresInSourceLayersWithIdentifiers:sourceLayers predicate:nil];
// Source not added yet, so features is 0
diff --git a/platform/darwin/test/MGLStyleLayerTests.h b/platform/darwin/test/MGLStyleLayerTests.h
index f0b889f022..c7577819b8 100644
--- a/platform/darwin/test/MGLStyleLayerTests.h
+++ b/platform/darwin/test/MGLStyleLayerTests.h
@@ -1,6 +1,9 @@
#import <Mapbox/Mapbox.h>
#import <XCTest/XCTest.h>
+#define MGLConstantExpression(constant) \
+ [NSExpression expressionForConstantValue:constant]
+
@interface MGLStyleLayerTests : XCTestCase <MGLMapViewDelegate>
@property (nonatomic, copy, readonly, class) NSString *layerType;
@@ -11,7 +14,7 @@
@interface NSString (MGLStyleLayerTestAdditions)
-@property (nonatomic, readonly, copy) NS_ARRAY_OF(NSString *) *lexicalClasses;
+@property (nonatomic, readonly, copy) NSArray<NSString *> *lexicalClasses;
@property (nonatomic, readonly, copy) NSString *lemma;
@end
diff --git a/platform/darwin/test/MGLStyleLayerTests.m b/platform/darwin/test/MGLStyleLayerTests.m
index b51fa02af4..52b36dba00 100644
--- a/platform/darwin/test/MGLStyleLayerTests.m
+++ b/platform/darwin/test/MGLStyleLayerTests.m
@@ -33,7 +33,7 @@
}
- (void)testPropertyName:(NSString *)name isBoolean:(BOOL)isBoolean {
- NS_MUTABLE_ARRAY_OF(NSString *) *components = [name componentsSeparatedByString:@"-"].mutableCopy;
+ NSMutableArray<NSString *> *components = [name componentsSeparatedByString:@"-"].mutableCopy;
if (isBoolean) {
if ([components.firstObject isEqualToString:@"is"]) {
[components removeObjectAtIndex:0];
@@ -67,7 +67,7 @@
@implementation NSString (MGLStyleLayerTestAdditions)
-- (NS_ARRAY_OF(NSString *) *)lexicalClasses {
+- (NSArray<NSString *> *)lexicalClasses {
NSOrthography *orthography = [NSOrthography orthographyWithDominantScript:@"Latn"
languageMap:@{@"Latn": @[@"en"]}];
NSLinguisticTaggerOptions options = (NSLinguisticTaggerOmitPunctuation
diff --git a/platform/darwin/test/MGLStyleLayerTests.mm.ejs b/platform/darwin/test/MGLStyleLayerTests.mm.ejs
index 5fdfc3d44e..f70f0bba23 100644
--- a/platform/darwin/test/MGLStyleLayerTests.mm.ejs
+++ b/platform/darwin/test/MGLStyleLayerTests.mm.ejs
@@ -23,7 +23,7 @@
return @"<%- type %>";
}
-<% if (type !== 'background' && type !== 'raster') { -%>
+<% if (type !== 'background' && type !== 'raster' && type !== 'hillshade') { -%>
- (void)testPredicates {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
@@ -36,8 +36,8 @@
XCTAssertNil(layer.sourceLayerIdentifier);
XCTAssertNil(layer.predicate);
- layer.predicate = [NSPredicate predicateWithValue:NO];
- XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
+ layer.predicate = [NSPredicate predicateWithFormat:@"$featureIdentifier = 1"];
+ XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithFormat:@"$featureIdentifier = 1"]);
layer.predicate = nil;
XCTAssertNil(layer.predicate);
}
@@ -59,50 +59,56 @@
MGLTransition transitionTest = MGLTransitionMake(5, 4);
<% for (const property of properties) { -%>
+<% if (property.name === 'heatmap-color') continue; -%>
// <%- originalPropertyName(property) %>
{
XCTAssertTrue(rawLayer->get<%- camelize(originalPropertyName(property)) %>().isUndefined(),
@"<%- originalPropertyName(property) %> should be unset initially.");
- MGLStyleValue<<%- propertyType(property) %>> *defaultStyleValue = layer.<%- objCName(property) %>;
+ NSExpression *defaultExpression = layer.<%- objCName(property) %>;
- MGLStyleValue<<%- propertyType(property) %>> *constantStyleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithRawValue:<%- objCTestValue(property, type, 3) %>];
- layer.<%- objCName(property) %> = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:<%- objCTestValue(property, type, true, 3) %>];
+ layer.<%- objCName(property) %> = constantExpression;
<% if (property["property-function"]) { -%>
mbgl::style::DataDrivenPropertyValue<<%- mbglType(property) %>> propertyValue = { <%- mbglTestValue(property, type) %> };
<% } else { -%>
mbgl::style::PropertyValue<<%- mbglType(property) %>> propertyValue = { <%- mbglTestValue(property, type) %> };
<% } -%>
XCTAssertEqual(rawLayer->get<%- camelize(originalPropertyName(property)) %>(), propertyValue,
- @"Setting <%- objCName(property) %> to a constant value should update <%- originalPropertyName(property) %>.");
- XCTAssertEqualObjects(layer.<%- objCName(property) %>, constantStyleValue,
- @"<%- objCName(property) %> should round-trip constant values.");
-
- MGLStyleValue<<%- propertyType(property) %>> * functionStyleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.<%- objCName(property) %> = functionStyleValue;
-
- mbgl::style::IntervalStops<<%- mbglType(property) %>> intervalStops = { {{18, <%- mbglTestValue(property, type) %>}} };
+ @"Setting <%- objCName(property) %> to a constant value expression should update <%- originalPropertyName(property) %>.");
+ XCTAssertEqualObjects(layer.<%- objCName(property) %>, constantExpression,
+ @"<%- objCName(property) %> should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:<%- objCTestValue(property, type, false, 3) %>];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.<%- objCName(property) %> = functionExpression;
+
+ mbgl::style::IntervalStops<<%- mbglType(property) %>> intervalStops = {{
+ { -INFINITY, <%- mbglTestValue(property, type) %> },
+ { 18, <%- mbglTestValue(property, type) %> },
+ }};
propertyValue = mbgl::style::CameraFunction<<%- mbglType(property) %>> { intervalStops };
XCTAssertEqual(rawLayer->get<%- camelize(originalPropertyName(property)) %>(), propertyValue,
- @"Setting <%- objCName(property) %> to a camera function should update <%- originalPropertyName(property) %>.");
- XCTAssertEqualObjects(layer.<%- objCName(property) %>, functionStyleValue,
- @"<%- objCName(property) %> should round-trip camera functions.");
+ @"Setting <%- objCName(property) %> to a camera expression should update <%- originalPropertyName(property) %>.");
+ XCTAssertEqualObjects(layer.<%- objCName(property) %>, functionExpression,
+ @"<%- objCName(property) %> should round-trip camera expressions.");
<% if (property["property-function"] && isInterpolatable(property)) { -%>
- functionStyleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.<%- objCName(property) %> = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.<%- objCName(property) %> = functionExpression;
mbgl::style::ExponentialStops<<%- mbglType(property) %>> exponentialStops = { {{18, <%- mbglTestValue(property, type) %>}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<<%- mbglType(property) %>> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->get<%- camelize(originalPropertyName(property)) %>(), propertyValue,
- @"Setting <%- objCName(property) %> to a source function should update <%- originalPropertyName(property) %>.");
- XCTAssertEqualObjects(layer.<%- objCName(property) %>, functionStyleValue,
- @"<%- objCName(property) %> should round-trip source functions.");
+ @"Setting <%- objCName(property) %> to a data expression should update <%- originalPropertyName(property) %>.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.<%- objCName(property) %>, pedanticFunctionExpression,
+ @"<%- objCName(property) %> should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.<%- objCName(property) %> = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.<%- objCName(property) %> = functionExpression;
std::map<float, <%- mbglType(property) %>> innerStops { {18, <%- mbglTestValue(property, type) %>} };
mbgl::style::CompositeExponentialStops<<%- mbglType(property) %>> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -110,24 +116,26 @@
propertyValue = mbgl::style::CompositeFunction<<%- mbglType(property) %>> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->get<%- camelize(originalPropertyName(property)) %>(), propertyValue,
- @"Setting <%- objCName(property) %> to a composite function should update <%- originalPropertyName(property) %>.");
- XCTAssertEqualObjects(layer.<%- objCName(property) %>, functionStyleValue,
- @"<%- objCName(property) %> should round-trip composite functions.");
+ @"Setting <%- objCName(property) %> to a camera-data expression should update <%- originalPropertyName(property) %>.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.<%- objCName(property) %>, pedanticFunctionExpression,
+ @"<%- objCName(property) %> should round-trip camera-data expressions.");
<% } -%>
<% if (!property.required) { -%>
layer.<%- objCName(property) %> = nil;
XCTAssertTrue(rawLayer->get<%- camelize(originalPropertyName(property)) %>().isUndefined(),
@"Unsetting <%- objCName(property) %> should return <%- originalPropertyName(property) %> to the default value.");
- XCTAssertEqualObjects(layer.<%- objCName(property) %>, defaultStyleValue,
+ XCTAssertEqualObjects(layer.<%- objCName(property) %>, defaultExpression,
@"<%- objCName(property) %> should return the default value after being unset.");
<% } -%>
<% if (!property["property-function"]) { -%>
- functionStyleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.<%- objCName(property) %> = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.<%- objCName(property) %> = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.<%- objCName(property) %> = functionExpression, NSException, NSInvalidArgumentException, @"MGL<%- camelize(type) %>Layer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.<%- objCName(property) %> = functionExpression, NSException, NSInvalidArgumentException, @"MGL<%- camelize(type) %>Layer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
<% } -%>
<% if (property["transition"] && !property.original) { -%>
// Transition property test
@@ -146,6 +154,7 @@
- (void)testPropertyNames {
<% for (const property of properties) { -%>
+<% if (property.name === 'heatmap-color') continue; -%>
[self testPropertyName:@"<%- property.getter || property.name %>" isBoolean:<%- property.type === 'boolean' ? 'YES' : 'NO' %>];
<% } -%>
}
diff --git a/platform/darwin/test/MGLStyleTests.mm b/platform/darwin/test/MGLStyleTests.mm
index 8f610e338c..6048f39ea3 100644
--- a/platform/darwin/test/MGLStyleTests.mm
+++ b/platform/darwin/test/MGLStyleTests.mm
@@ -1,6 +1,7 @@
#import <Mapbox/Mapbox.h>
#import "NSBundle+MGLAdditions.h"
+#import "MGLVectorTileSource_Private.h"
#import <mbgl/util/default_styles.hpp>
@@ -64,12 +65,6 @@
XCTAssertEqualObjects([MGLStyle darkStyleURL].absoluteString, @(mbgl::util::default_styles::dark.url));
XCTAssertEqualObjects([MGLStyle satelliteStyleURL].absoluteString, @(mbgl::util::default_styles::satellite.url));
XCTAssertEqualObjects([MGLStyle satelliteStreetsStyleURL].absoluteString, @(mbgl::util::default_styles::satelliteStreets.url));
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- XCTAssertEqualObjects([MGLStyle emeraldStyleURL].absoluteString, @"mapbox://styles/mapbox/emerald-v8");
- XCTAssertEqualObjects([MGLStyle hybridStyleURL].absoluteString, @"mapbox://styles/mapbox/satellite-hybrid-v8");
-#pragma clang diagnostic pop
}
- (void)testVersionedStyleURLs {
@@ -99,19 +94,8 @@
@(mbgl::util::default_styles::satelliteStreets.url));
XCTAssertEqualObjects([MGLStyle satelliteStreetsStyleURLWithVersion:99].absoluteString,
@"mapbox://styles/mapbox/satellite-streets-v99");
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- XCTAssertEqualObjects([MGLStyle trafficDayStyleURLWithVersion:mbgl::util::default_styles::trafficDay.currentVersion].absoluteString,
- @(mbgl::util::default_styles::trafficDay.url));
- XCTAssertEqualObjects([MGLStyle trafficDayStyleURLWithVersion:99].absoluteString,
- @"mapbox://styles/mapbox/traffic-day-v99");
- XCTAssertEqualObjects([MGLStyle trafficNightStyleURLWithVersion:mbgl::util::default_styles::trafficNight.currentVersion].absoluteString,
- @(mbgl::util::default_styles::trafficNight.url));
- XCTAssertEqualObjects([MGLStyle trafficNightStyleURLWithVersion:99].absoluteString,
- @"mapbox://styles/mapbox/traffic-night-v99");
-#pragma clang diagnostic pop
-
- static_assert(8 == mbgl::util::default_styles::numOrderedStyles,
+
+ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
"MGLStyleTests isn’t testing all the styles in mbgl::util::default_styles.");
}
@@ -143,7 +127,7 @@
NSString *styleHeader = self.stringWithContentsOfStyleHeader;
NSError *versionedMethodError;
- NSString *versionedMethodExpressionString = @(R"RE(^\+\s*\(NSURL\s*\*\s*\)\s*\w+StyleURLWithVersion\s*:\s*\(\s*NSInteger\s*\)\s*version\s*\b)RE");
+ NSString *versionedMethodExpressionString = @(R"RE(^\+\s*\(NSURL\s*\*\s*\)\s*(?!traffic)\w+StyleURLWithVersion\s*:\s*\(\s*NSInteger\s*\)\s*version\s*\b)RE");
NSRegularExpression *versionedMethodExpression = [NSRegularExpression regularExpressionWithPattern:versionedMethodExpressionString options:NSRegularExpressionAnchorsMatchLines error:&versionedMethodError];
XCTAssertNil(versionedMethodError, @"Error compiling regular expression to search for versioned methods.");
NSUInteger numVersionedMethodDeclarations = [versionedMethodExpression numberOfMatchesInString:styleHeader options:0 range:NSMakeRange(0, styleHeader.length)];
@@ -174,89 +158,89 @@
[self.style addSource:shapeSource];
XCTAssertThrowsSpecificNamed([self.style addSource:shapeSource], NSException, @"MGLRedundantSourceException");
- MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithIdentifier:@"rasterSource" configurationURL:[NSURL URLWithString:@".json"] tileSize:42];
- [self.style addSource:rasterSource];
- XCTAssertThrowsSpecificNamed([self.style addSource:rasterSource], NSException, @"MGLRedundantSourceException");
+ MGLRasterTileSource *rasterTileSource = [[MGLRasterTileSource alloc] initWithIdentifier:@"rasterTileSource" configurationURL:[NSURL URLWithString:@".json"] tileSize:42];
+ [self.style addSource:rasterTileSource];
+ XCTAssertThrowsSpecificNamed([self.style addSource:rasterTileSource], NSException, @"MGLRedundantSourceException");
- MGLVectorSource *vectorSource = [[MGLVectorSource alloc] initWithIdentifier:@"vectorSource" configurationURL:[NSURL URLWithString:@".json"]];
- [self.style addSource:vectorSource];
- XCTAssertThrowsSpecificNamed([self.style addSource:vectorSource], NSException, @"MGLRedundantSourceException");
+ MGLVectorTileSource *vectorTileSource = [[MGLVectorTileSource alloc] initWithIdentifier:@"vectorTileSource" configurationURL:[NSURL URLWithString:@".json"]];
+ [self.style addSource:vectorTileSource];
+ XCTAssertThrowsSpecificNamed([self.style addSource:vectorTileSource], NSException, @"MGLRedundantSourceException");
}
- (void)testAddingSourcesWithDuplicateIdentifiers {
- MGLVectorSource *source1 = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" configurationURL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
- MGLVectorSource *source2 = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" configurationURL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
+ MGLVectorTileSource *source1 = [[MGLVectorTileSource alloc] initWithIdentifier:@"my-source" configurationURL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
+ MGLVectorTileSource *source2 = [[MGLVectorTileSource alloc] initWithIdentifier:@"my-source" configurationURL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
[self.style addSource: source1];
XCTAssertThrowsSpecificNamed([self.style addSource: source2], NSException, @"MGLRedundantSourceIdentifierException");
}
- (void)testRemovingSourcesBeforeAddingThem {
- MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithIdentifier:@"raster-source" tileURLTemplates:@[] options:nil];
- [self.style removeSource:rasterSource];
- [self.style addSource:rasterSource];
- XCTAssertNotNil([self.style sourceWithIdentifier:rasterSource.identifier]);
+ MGLRasterTileSource *rasterTileSource = [[MGLRasterTileSource alloc] initWithIdentifier:@"raster-tile-source" tileURLTemplates:@[] options:nil];
+ [self.style removeSource:rasterTileSource];
+ [self.style addSource:rasterTileSource];
+ XCTAssertNotNil([self.style sourceWithIdentifier:rasterTileSource.identifier]);
MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"shape-source" shape:nil options:nil];
[self.style removeSource:shapeSource];
[self.style addSource:shapeSource];
XCTAssertNotNil([self.style sourceWithIdentifier:shapeSource.identifier]);
- MGLVectorSource *vectorSource = [[MGLVectorSource alloc] initWithIdentifier:@"vector-source" tileURLTemplates:@[] options:nil];
- [self.style removeSource:vectorSource];
- [self.style addSource:vectorSource];
- XCTAssertNotNil([self.style sourceWithIdentifier:vectorSource.identifier]);
+ MGLVectorTileSource *vectorTileSource = [[MGLVectorTileSource alloc] initWithIdentifier:@"vector-tile-source" tileURLTemplates:@[] options:nil];
+ [self.style removeSource:vectorTileSource];
+ [self.style addSource:vectorTileSource];
+ XCTAssertNotNil([self.style sourceWithIdentifier:vectorTileSource.identifier]);
}
- (void)testAddingSourceOfTypeABeforeSourceOfTypeBWithSameIdentifier {
- // Add a raster source
- MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
- [self.style addSource:rasterSource];
+ // Add a raster tile source
+ MGLRasterTileSource *rasterTileSource = [[MGLRasterTileSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
+ [self.style addSource:rasterTileSource];
- // Attempt to remove an image source with the same identifier as the raster source
+ // Attempt to remove an image source with the same identifier as the raster tile source
MGLImageSource *imageSource = [[MGLImageSource alloc] initWithIdentifier:@"some-identifier" coordinateQuad: { } URL:[NSURL URLWithString:@"http://host/image.png"]];
[self.style removeSource:imageSource];
- // The raster source should still be added
- XCTAssertTrue([[self.style sourceWithIdentifier:rasterSource.identifier] isMemberOfClass:[MGLRasterSource class]]);
+ // The raster tile source should still be added
+ XCTAssertTrue([[self.style sourceWithIdentifier:rasterTileSource.identifier] isMemberOfClass:[MGLRasterTileSource class]]);
- // Remove the raster source
- [self.style removeSource:rasterSource];
+ // Remove the raster tile source
+ [self.style removeSource:rasterTileSource];
// Add the shape source
[self.style addSource:imageSource];
- // Attempt to remove a vector source with the same identifer as the shape source
- MGLVectorSource *vectorSource = [[MGLVectorSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
- [self.style removeSource:vectorSource];
+ // Attempt to remove a vector tile source with the same identifer as the shape source
+ MGLVectorTileSource *vectorTileSource = [[MGLVectorTileSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
+ [self.style removeSource:vectorTileSource];
// The image source should still be added
XCTAssertTrue([[self.style sourceWithIdentifier:imageSource.identifier] isMemberOfClass:[MGLImageSource class]]);
// Remove the image source
[self.style removeSource:imageSource];
- // Add the vector source
- [self.style addSource:vectorSource];
+ // Add the vector tile source
+ [self.style addSource:vectorTileSource];
- // Attempt to remove the previously created raster source that has the same identifer as the shape source
- [self.style removeSource:rasterSource];
- // The vector source should still be added
- XCTAssertTrue([[self.style sourceWithIdentifier:imageSource.identifier] isMemberOfClass:[MGLVectorSource class]]);
+ // Attempt to remove the previously created raster tile source that has the same identifer as the shape source
+ [self.style removeSource:rasterTileSource];
+ // The vector tile source should still be added
+ XCTAssertTrue([[self.style sourceWithIdentifier:imageSource.identifier] isMemberOfClass:[MGLVectorTileSource class]]);
}
- (void)testRemovingSourceInUse {
- // Add a raster source
- MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
- [self.style addSource:rasterSource];
+ // Add a raster tile source
+ MGLRasterTileSource *rasterTileSource = [[MGLRasterTileSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
+ [self.style addSource:rasterTileSource];
// Add a layer using it
- MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fillLayer" source:rasterSource];
+ MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fillLayer" source:rasterTileSource];
[self.style addLayer:fillLayer];
- // Attempt to remove the raster source
- [self.style removeSource:rasterSource];
+ // Attempt to remove the raster tile source
+ [self.style removeSource:rasterTileSource];
// Ensure it is still there
- XCTAssertTrue([[self.style sourceWithIdentifier:rasterSource.identifier] isMemberOfClass:[MGLRasterSource class]]);
+ XCTAssertTrue([[self.style sourceWithIdentifier:rasterTileSource.identifier] isMemberOfClass:[MGLRasterTileSource class]]);
}
- (void)testLayers {
@@ -306,7 +290,7 @@
- (void)testAddingLayersWithDuplicateIdentifiers {
// Just some source
- MGLVectorSource *source = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" configurationURL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
+ MGLVectorTileSource *source = [[MGLVectorTileSource alloc] initWithIdentifier:@"my-source" configurationURL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
[self.style addSource: source];
// Add initial layer
@@ -383,13 +367,6 @@
return styleHeader;
}
-- (void)testClasses {
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- XCTAssertEqual(self.style.styleClasses.count, 0);
-#pragma clang diagnostic pop
-}
-
- (void)testImages {
NSString *imageName = @"TrackingLocationMask";
#if TARGET_OS_IPHONE
@@ -443,4 +420,45 @@
XCTAssertEqualObjects(layers[startIndex++].identifier, layer4.identifier);
}
+#pragma mark Localization tests
+
+- (void)testLanguageMatching {
+ {
+ NSArray *preferences = @[@"en"];
+ XCTAssertEqualObjects([MGLVectorTileSource preferredMapboxStreetsLanguageForPreferences:preferences], @"en");
+ }
+ {
+ NSArray *preferences = @[@"en-US"];
+ XCTAssertEqualObjects([MGLVectorTileSource preferredMapboxStreetsLanguageForPreferences:preferences], @"en");
+ }
+ {
+ NSArray *preferences = @[@"fr"];
+ XCTAssertEqualObjects([MGLVectorTileSource preferredMapboxStreetsLanguageForPreferences:preferences], @"fr");
+ }
+ {
+ NSArray *preferences = @[@"zh-Hans"];
+ XCTAssertEqualObjects([MGLVectorTileSource preferredMapboxStreetsLanguageForPreferences:preferences], @"zh-Hans");
+ }
+ {
+ NSArray *preferences = @[@"zh-Hans", @"en"];
+ XCTAssertEqualObjects([MGLVectorTileSource preferredMapboxStreetsLanguageForPreferences:preferences], @"zh-Hans");
+ }
+ {
+ NSArray *preferences = @[@"zh-Hant"];
+ XCTAssertNil([MGLVectorTileSource preferredMapboxStreetsLanguageForPreferences:preferences]);
+ }
+ {
+ NSArray *preferences = @[@"tlh"];
+ XCTAssertNil([MGLVectorTileSource preferredMapboxStreetsLanguageForPreferences:preferences]);
+ }
+ {
+ NSArray *preferences = @[@"tlh", @"en"];
+ XCTAssertEqualObjects([MGLVectorTileSource preferredMapboxStreetsLanguageForPreferences:preferences], @"en");
+ }
+ {
+ NSArray *preferences = @[@"mul"];
+ XCTAssertNil([MGLVectorTileSource preferredMapboxStreetsLanguageForPreferences:preferences]);
+ }
+}
+
@end
diff --git a/platform/darwin/test/MGLStyleValueTests.h b/platform/darwin/test/MGLStyleValueTests.h
deleted file mode 100644
index a563de39f0..0000000000
--- a/platform/darwin/test/MGLStyleValueTests.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#import <XCTest/XCTest.h>
-
-@interface MGLStyleValueTests : XCTestCase
-@end
diff --git a/platform/darwin/test/MGLStyleValueTests.m b/platform/darwin/test/MGLStyleValueTests.m
deleted file mode 100644
index cd6eec8324..0000000000
--- a/platform/darwin/test/MGLStyleValueTests.m
+++ /dev/null
@@ -1,113 +0,0 @@
-#import <XCTest/XCTest.h>
-#import <Mapbox/Mapbox.h>
-
-@interface MGLStyleValueTests : XCTestCase
-@end
-
-@implementation MGLStyleValueTests
-
-- (void)testStoplessFunction {
- XCTAssertThrowsSpecificNamed([MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential cameraStops:@{} options:nil], NSException, NSInvalidArgumentException, @"Stopless function should raise an exception");
-}
-
-- (void)testDeprecatedFunctions {
- MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"test"
- shape:nil
- options:nil];
- MGLSymbolStyleLayer *symbolStyleLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"symbolLayer"
- source:shapeSource];
- MGLCircleStyleLayer *circleStyleLayer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"circleLayer"
- source:shapeSource];
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- // deprecated function, stops with float values
- NSDictionary<NSNumber *, MGLStyleValue<NSNumber *> *> *stops = @{
- @1: [MGLStyleValue<NSNumber *> valueWithRawValue:@0],
- @2: [MGLStyleValue<NSNumber *> valueWithRawValue:@1],
- @3: [MGLStyleValue<NSNumber *> valueWithRawValue:@2],
- @4: [MGLStyleValue<NSNumber *> valueWithRawValue:@0],
- };
- MGLStyleValue<NSNumber *> *iconHaloBlurStyleValue =
- [MGLStyleValue<NSNumber *> valueWithInterpolationBase:1.0 stops:stops];
- symbolStyleLayer.iconHaloBlur = iconHaloBlurStyleValue;
- XCTAssertEqualObjects(symbolStyleLayer.iconHaloBlur, iconHaloBlurStyleValue);
-
- // deprecated function, stops with boolean values
- stops = @{
- @1: [MGLStyleValue<NSNumber *> valueWithRawValue:@YES],
- @2: [MGLStyleValue<NSNumber *> valueWithRawValue:@NO],
- @3: [MGLStyleValue<NSNumber *> valueWithRawValue:@YES],
- @4: [MGLStyleValue<NSNumber *> valueWithRawValue:@NO],
- };
- MGLStyleValue<NSNumber *> *iconAllowsOverlapStyleValue =
- [MGLStyleValue<NSNumber *> valueWithInterpolationBase:1.0 stops:stops];
- symbolStyleLayer.iconAllowsOverlap = iconAllowsOverlapStyleValue;
- // iconAllowsOverlap is boolean so mgl and mbgl conversions will coerce the developers stops into interval stops
- MGLStyleValue<NSNumber *> *expectedIconAllowsOverlapStyleValue =
- [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval
- cameraStops:stops
- options:nil];
- XCTAssertEqualObjects(symbolStyleLayer.iconAllowsOverlap, expectedIconAllowsOverlapStyleValue);
-
- ///
- // creating and using MGLStyleFunctions directly
- ///
-
- NSDictionary<NSNumber *, MGLStyleValue<NSNumber *> *> *circleRadiusStops = @{
- @0: [MGLStyleValue<NSNumber *> valueWithRawValue:@10],
- @20: [MGLStyleValue<NSNumber *> valueWithRawValue:@5],
- };
- MGLStyleFunction<NSNumber *> *circleRadiusFunction =
- [MGLStyleFunction<NSNumber *> functionWithInterpolationBase:1.0
- stops:circleRadiusStops];
- circleStyleLayer.circleRadius = circleRadiusFunction;
- MGLStyleValue<NSNumber *> *expectedCircleRadiusFunction =
- [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential
- cameraStops:circleRadiusStops
- options:nil];
- // setting a data driven property to an MGLStyleFunction should return an exponential camera function
- XCTAssertEqualObjects(circleStyleLayer.circleRadius, expectedCircleRadiusFunction);
-
- CGVector circleTranslationOne = CGVectorMake(100, 0);
- CGVector circleTranslationTwo = CGVectorMake(0, 0);
-#if TARGET_OS_IPHONE
- NSValue *circleTranslationValueOne = [NSValue valueWithCGVector:circleTranslationOne];
- NSValue *circleTranslationValueTwo = [NSValue valueWithCGVector:circleTranslationTwo];
-#else
- NSValue *circleTranslationValueOne = [NSValue value:&circleTranslationOne withObjCType:@encode(CGVector)];
- NSValue *circleTranslationValueTwo = [NSValue value:&circleTranslationTwo withObjCType:@encode(CGVector)];
-#endif
-
- NSDictionary<NSNumber *, MGLStyleValue<NSValue *> *> *circleTranslationStops = @{
- @0: [MGLStyleValue<NSValue *> valueWithRawValue:circleTranslationValueOne],
- @10: [MGLStyleValue<NSValue *> valueWithRawValue:circleTranslationValueTwo],
- };
- MGLStyleFunction<NSValue *> *circleTranslationFunction =
- [MGLStyleFunction<NSValue *> functionWithInterpolationBase:1.0
- stops:circleTranslationStops];
- circleStyleLayer.circleTranslation = circleTranslationFunction;
- MGLStyleValue<NSValue *> *expectedCircleTranslationFunction =
- [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeExponential
- cameraStops:circleTranslationStops
- options:nil];
- // setting a non-data driven, interpolatable property to an MGLStyleFunction should return an exponential camera function
- XCTAssertEqualObjects(circleStyleLayer.circleTranslation, expectedCircleTranslationFunction);
-
- NSDictionary<NSNumber *, MGLStyleValue<NSNumber *> *> *iconOptionalStops = @{
- @0: [MGLStyleValue<NSNumber *> valueWithRawValue:@NO],
- @20: [MGLStyleValue<NSNumber *> valueWithRawValue:@YES],
- };
- MGLStyleFunction<NSNumber *> *iconOptionalFunction =
- [MGLStyleFunction<NSNumber *> valueWithInterpolationBase:1.0
- stops:iconOptionalStops];
- symbolStyleLayer.iconOptional = iconOptionalFunction;
- MGLStyleValue<NSNumber *> *expectedIconOptionalFunction =
- [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval
- cameraStops:iconOptionalStops
- options:nil];
- XCTAssertEqualObjects(symbolStyleLayer.iconOptional, expectedIconOptionalFunction);
-#pragma clang diagnostic pop
-}
-
-@end
diff --git a/platform/darwin/test/MGLStyleValueTests.swift b/platform/darwin/test/MGLStyleValueTests.swift
deleted file mode 100644
index c559037588..0000000000
--- a/platform/darwin/test/MGLStyleValueTests.swift
+++ /dev/null
@@ -1,362 +0,0 @@
-import XCTest
-import Mapbox
-
-#if os(iOS) || os(watchOS) || os(tvOS)
-typealias MGLColor = UIColor
-#elseif os(macOS)
-typealias MGLColor = NSColor
-#endif
-
-#if swift(>=3.2)
-#else
-func XCTAssertEqual<T: FloatingPoint>(_ lhs: @autoclosure () throws -> T, _ rhs: @autoclosure () throws -> T, accuracy: T) {
- XCTAssertEqualWithAccuracy(lhs, rhs, accuracy: accuracy)
-}
-#endif
-
-extension MGLStyleValueTests {
-
- struct Color {
- var red: CGFloat = 0
- var green: CGFloat = 0
- var blue: CGFloat = 0
- var alpha: CGFloat = 0
- }
-
- func assertColorsEqualWithAccuracy(_ actual: MGLColor, _ expected: MGLColor, accuracy: Float = 1/255) {
- var actualColor = Color()
- var expectedColor = Color()
-
- actual.getRed(&actualColor.red, green: &actualColor.green, blue: &actualColor.blue, alpha: &actualColor.alpha)
- expected.getRed(&expectedColor.red, green: &expectedColor.green, blue: &expectedColor.blue, alpha: &expectedColor.alpha)
-
- XCTAssertEqual(Float(actualColor.red), Float(expectedColor.red), accuracy: accuracy)
- XCTAssertEqual(Float(actualColor.green), Float(expectedColor.green), accuracy: accuracy)
- XCTAssertEqual(Float(actualColor.blue), Float(expectedColor.blue), accuracy: accuracy)
- XCTAssertEqual(Float(actualColor.alpha), Float(expectedColor.alpha), accuracy: accuracy)
- }
-
- func assertColorValuesEqual(_ actual: MGLStyleValue<MGLColor>, _ expected: MGLStyleValue<MGLColor>) {
- guard type(of: actual) == type(of: expected) else {
- XCTFail("Expected \(type(of: expected)), but found \(type(of: actual)) instead.")
- return
- }
-
- if let actualConstant = actual as? MGLConstantStyleValue<MGLColor> {
- assertColorsEqualWithAccuracy(actualConstant.rawValue, (expected as! MGLConstantStyleValue<MGLColor>).rawValue)
- } else if let actualFunction = actual as? MGLStyleFunction<MGLColor>,
- let expectedFunction = expected as? MGLStyleFunction<MGLColor> {
-
- // unless we have stops, there's no need for a custom comparison - default to plain == assertion
- guard let actualStops = actualFunction.stops, let expectedStops = expectedFunction.stops else {
- XCTAssertEqual(actualFunction, expectedFunction)
- return
- }
-
- guard expectedStops is [String: Any] || expectedStops is [Float:Any] else {
- XCTFail("Stop levels must be String or Float.")
- return
- }
-
- XCTAssertEqual(actualFunction.interpolationBase, expectedFunction.interpolationBase)
- XCTAssertEqual(actualFunction.interpolationMode, expectedFunction.interpolationMode)
- if let actualFunction = actualFunction as? MGLSourceStyleFunction<MGLColor>,
- let expectedFunction = expectedFunction as? MGLSourceStyleFunction<MGLColor> {
- XCTAssertEqual(actualFunction.defaultValue, expectedFunction.defaultValue)
- } else if let actualFunction = actualFunction as? MGLCompositeStyleFunction<MGLColor>,
- let expectedFunction = expectedFunction as? MGLCompositeStyleFunction<MGLColor> {
- XCTAssertEqual(actualFunction.defaultValue, expectedFunction.defaultValue)
- }
-
- func assertStopEqual (_ actualValue: Any?, _ expectedValue: Any?) {
- guard type(of: actualValue) == type(of: expectedValue) else {
- XCTFail("Expected stop value of type \(type(of: expectedValue)), but found \(type(of: actualValue)) instead.")
- return
- }
- if let actualValue = actualValue as? MGLConstantStyleValue<MGLColor>,
- let expectedValue = expectedValue as? MGLConstantStyleValue<MGLColor> {
- assertColorsEqualWithAccuracy(actualValue.rawValue, expectedValue.rawValue)
- } else if let actualValue = actualValue as? MGLConstantStyleValue<AnyObject>,
- let expectedValue = expectedValue as? MGLConstantStyleValue<AnyObject> {
- XCTAssertEqual(actualValue, expectedValue)
- } else {
- XCTFail("Unsupported stop value type \(type(of: actualValue)).")
- }
- }
-
- XCTAssertEqual(actualStops.count, expectedStops.count)
- if let actualStops = actualStops as? [String:Any], let expectedStops = expectedStops as? [String: Any] {
- for (key, value) in actualStops {
- assertStopEqual(value, expectedStops[key])
- }
- } else if let actualStops = actualStops as? [Float:Any], let expectedStops = expectedStops as? [Float:Any] {
- for (key, value) in actualStops {
- assertStopEqual(value, expectedStops[key])
- }
- } else {
- XCTFail("Expected stops of type \(type(of: Array(expectedStops.keys)).Index.self), but found \(type(of: Array(actualStops.keys)).Index.self) instead.")
- return
- }
- } else {
- XCTFail("MGLStyleValue<MGLColor> must be either a constant or a style function.")
- }
- }
-
- func testConstantValues() {
- let shapeSource = MGLShapeSource(identifier: "source", shape: nil, options: nil)
- let symbolStyleLayer = MGLSymbolStyleLayer(identifier: "symbolLayer", source: shapeSource)
- let circleStyleLayer = MGLCircleStyleLayer(identifier: "circleLayer", source: shapeSource)
-
- // Boolean
- symbolStyleLayer.iconAllowsOverlap = MGLConstantStyleValue(rawValue: true)
- XCTAssertEqual((symbolStyleLayer.iconAllowsOverlap as! MGLConstantStyleValue<NSNumber>).rawValue, true)
-
- // Number
- symbolStyleLayer.iconHaloWidth = MGLConstantStyleValue(rawValue: 3)
- XCTAssertEqual((symbolStyleLayer.iconHaloWidth as! MGLConstantStyleValue<NSNumber>).rawValue, 3)
-
- // String
- symbolStyleLayer.text = MGLConstantStyleValue(rawValue: "{name}")
- XCTAssertEqual((symbolStyleLayer.text as! MGLConstantStyleValue<NSString>).rawValue, "{name}")
-
- var circleTranslationOne = CGVector(dx: 100, dy: 0)
- let circleTranslationValueOne = NSValue(bytes: &circleTranslationOne, objCType: "{CGVector=dd}")
-
- // non-data-driven (interpolatable property value), set to constant style value
- let expectedCircleTranslationValue = MGLStyleValue<NSValue>(rawValue: circleTranslationValueOne)
- circleStyleLayer.circleTranslation = expectedCircleTranslationValue
- XCTAssertEqual(circleStyleLayer.circleTranslation, expectedCircleTranslationValue)
-
- // non-data-driven (enumeration property value), set to constant style value
- let expectedCircleScaleAlignmentValue = MGLStyleValue<NSValue>(rawValue: NSValue(mglCircleScaleAlignment: .map))
- circleStyleLayer.circleScaleAlignment = expectedCircleScaleAlignmentValue
- XCTAssertEqual(circleStyleLayer.circleScaleAlignment, expectedCircleScaleAlignmentValue)
- }
-
- func testFunctionsWithNonDataDrivenProperties() {
- let shapeSource = MGLShapeSource(identifier: "test", shape: nil, options: nil)
- let circleStyleLayer = MGLCircleStyleLayer(identifier: "circleLayer", source: shapeSource)
-
- var circleTranslationOne = CGVector(dx: 100, dy: 0)
- let circleTranslationValueOne = NSValue(bytes: &circleTranslationOne, objCType: "{CGVector=dd}")
- var circleTranslationTwo = CGVector(dx: 0, dy: 0)
- let circleTranslationValueTwo = NSValue(bytes: &circleTranslationTwo, objCType: "{CGVector=dd}")
-
- let circleTranslationStops : [Float:MGLStyleValue<NSValue>] = [
- 0: MGLStyleValue<NSValue>(rawValue: circleTranslationValueOne),
- 10: MGLStyleValue<NSValue>(rawValue: circleTranslationValueTwo)
- ]
-
- // non-data-driven (interpolatable property value), camera function with CGVector (NSValue) stop values
- let expectedCircleTranslationValue = MGLStyleValue<NSValue>(
- interpolationMode: .interval,
- cameraStops: circleTranslationStops,
- options: nil
- )
- circleStyleLayer.circleTranslation = expectedCircleTranslationValue
- XCTAssertEqual(circleStyleLayer.circleTranslation, expectedCircleTranslationValue)
-
- // non-data-driven (enumeration property value), camera function with MGLCircleScaleAlignment enum (NSValue) stop values
- let scaleAlignmentStops : [Float:MGLStyleValue<NSValue>] = [
- 0: MGLStyleValue(rawValue: NSValue(mglCircleScaleAlignment: .map)),
- 10: MGLStyleValue(rawValue: NSValue(mglCircleScaleAlignment: .viewport))
- ]
- let expectedCircleScaleAlignmentValue = MGLStyleValue<NSValue>(
- interpolationMode: .interval,
- cameraStops: scaleAlignmentStops,
- options: nil
- )
- circleStyleLayer.circleScaleAlignment = expectedCircleScaleAlignmentValue
- XCTAssertEqual(circleStyleLayer.circleScaleAlignment, expectedCircleScaleAlignmentValue)
- }
-
- func testFunctionsWithDataDrivenProperties() {
- let shapeSource = MGLShapeSource(identifier: "test", shape: nil, options: nil)
- let circleStyleLayer = MGLCircleStyleLayer(identifier: "circleLayer", source: shapeSource)
-
- // data-driven, camera function with exponential color stop values
- let redGreenStops : [Float:MGLStyleValue<MGLColor>] = [
- 0: MGLStyleValue<MGLColor>(rawValue: .red),
- 10: MGLStyleValue<MGLColor>(rawValue: .red),
- 15: MGLStyleValue<MGLColor>(rawValue: .green)
- ]
- let expectedCircleColorValue = MGLStyleValue<MGLColor>(
- interpolationMode: .exponential,
- cameraStops: redGreenStops,
- options: [.interpolationBase: 10.0]
- )
- circleStyleLayer.circleColor = expectedCircleColorValue
- assertColorValuesEqual(circleStyleLayer.circleColor as! MGLStyleFunction<MGLColor>, expectedCircleColorValue as! MGLStyleFunction<MGLColor>)
-
- // data-driven, source function with categorical color stop values with string attribute keys
- let redOnlyStops = [
- "red": MGLStyleValue<MGLColor>(rawValue: .red)
- ]
- let expectedRedCategoricalValue = MGLStyleValue<MGLColor>(
- interpolationMode: .categorical,
- sourceStops: redOnlyStops,
- attributeName: "red",
- options: [.defaultValue: MGLStyleValue<MGLColor>(rawValue: .cyan)]
- )
- circleStyleLayer.circleColor = expectedRedCategoricalValue
- assertColorValuesEqual(circleStyleLayer.circleColor, expectedRedCategoricalValue)
-
- // data-driven, source function with categorical color stop values with integer attribute keys
- let greenOrangeStops : [Float:MGLStyleValue<MGLColor>] = [
- 0: MGLStyleValue<MGLColor>(rawValue: .green),
- 100: MGLStyleValue<MGLColor>(rawValue: .orange)
- ]
- let expectedGreenOrangeCategoricalValue = MGLStyleValue<MGLColor>(
- interpolationMode: .categorical,
- sourceStops: greenOrangeStops,
- attributeName: "temp",
- options: [.defaultValue: MGLStyleValue<MGLColor>(rawValue: .red)]
- )
- circleStyleLayer.circleColor = expectedGreenOrangeCategoricalValue
- assertColorValuesEqual(circleStyleLayer.circleColor, expectedGreenOrangeCategoricalValue)
-
- // data-driven, source function with exponential color stop values
- let expectedRedGreenSourceExponentialValue = MGLStyleValue<MGLColor>(
- interpolationMode: .exponential,
- sourceStops: redGreenStops,
- attributeName: "temp",
- options: nil
- )
- circleStyleLayer.circleColor = expectedRedGreenSourceExponentialValue
- assertColorValuesEqual(circleStyleLayer.circleColor, expectedRedGreenSourceExponentialValue)
-
- // data-driven, identity source function
- let expectedSourceIdentityValue = MGLStyleValue<MGLColor>(
- interpolationMode: .identity,
- sourceStops: nil,
- attributeName: "size",
- options: [.defaultValue: MGLStyleValue<MGLColor>(rawValue: .green)]
- )
- circleStyleLayer.circleColor = expectedSourceIdentityValue
- assertColorValuesEqual(circleStyleLayer.circleColor, expectedSourceIdentityValue)
-
- // data-driven, source function with categorical color stop values with boolean attribute keys
- let booleanCategoricalStops = [
- false: MGLStyleValue<NSNumber>(rawValue: 0),
- true: MGLStyleValue<NSNumber>(rawValue: 2)
- ]
- let expectedCircleBlurCategoricalValue = MGLStyleValue<NSNumber>(
- interpolationMode: .categorical,
- sourceStops: booleanCategoricalStops,
- attributeName: "fuzzy",
- options: [.defaultValue: MGLStyleValue<NSNumber>(rawValue: 42)]
- )
- circleStyleLayer.circleBlur = expectedCircleBlurCategoricalValue
- XCTAssertEqual(circleStyleLayer.circleBlur, expectedCircleBlurCategoricalValue)
-
- // data-driven, composite function with inner categorical color stop values with string attribute keys nested in outer camera stops
- let smallRadius = MGLStyleValue<NSNumber>(rawValue: 5)
- let mediumRadius = MGLStyleValue<NSNumber>(rawValue: 10)
- let largeRadius = MGLStyleValue<NSNumber>(rawValue: 20)
- let radiusCompositeCategoricalStops: [Float: [String: MGLStyleValue<NSNumber>]] = [
- 0: ["green": smallRadius],
- 10: ["green": smallRadius],
- 15: ["green": largeRadius],
- 20: ["green": largeRadius]
- ]
- let defaultRadius = MGLStyleValue<NSNumber>(rawValue: 2)
- let expectedCompositeCategoricalValue = MGLStyleValue<NSNumber>(
- interpolationMode: .categorical,
- compositeStops: radiusCompositeCategoricalStops,
- attributeName: "color",
- options: [.defaultValue: defaultRadius]
- )
- circleStyleLayer.circleRadius = expectedCompositeCategoricalValue
-
- var compositeValue = circleStyleLayer.circleRadius as! MGLCompositeStyleFunction
- var expectedCompositeValue = expectedCompositeCategoricalValue as! MGLCompositeStyleFunction
- XCTAssertEqual(compositeValue.attributeName, expectedCompositeValue.attributeName)
- XCTAssertEqual(compositeValue.stops as NSDictionary, radiusCompositeCategoricalStops as NSDictionary)
- XCTAssertEqual(compositeValue.interpolationMode, expectedCompositeValue.interpolationMode)
- XCTAssertEqual(compositeValue.defaultValue, expectedCompositeValue.defaultValue)
-
- // data-driven, composite function with inner exponential color stop values nested in outer camera stops
- let radiusCompositeExponentialOrIntervalStops: [Float: [Float: MGLStyleValue<NSNumber>]] = [
- 0: [0: MGLStyleValue<NSNumber>(rawValue: 5)],
- 10: [200: MGLStyleValue<NSNumber>(rawValue: 5)],
- 20: [200: MGLStyleValue<NSNumber>(rawValue: 20)]
- ]
-
- let expectedStops = [
- 0: [0: MGLStyleValue<NSNumber>(rawValue: 5)],
- 10: [200: MGLStyleValue<NSNumber>(rawValue: 5)],
- 20: [200: MGLStyleValue<NSNumber>(rawValue: 20)]
- ]
- circleStyleLayer.circleRadius = MGLStyleValue<NSNumber>(
- interpolationMode: .exponential,
- compositeStops: [
- 0: [0: MGLStyleValue<NSNumber>(rawValue: 5)],
- 10: [200: MGLStyleValue<NSNumber>(rawValue: 5)],
- 20: [200: MGLStyleValue<NSNumber>(rawValue: 20)]
- ],
- attributeName: "temp",
- options: [.defaultValue: mediumRadius]
- )
-
- let expectedCompositeExponentialValue = MGLStyleValue<NSNumber>(
- interpolationMode: .exponential,
- compositeStops: radiusCompositeExponentialOrIntervalStops,
- attributeName: "temp",
- options: [.defaultValue: mediumRadius]
- )
-
- compositeValue = circleStyleLayer.circleRadius as! MGLCompositeStyleFunction
- expectedCompositeValue = expectedCompositeExponentialValue as! MGLCompositeStyleFunction
- XCTAssertEqual(compositeValue.attributeName, expectedCompositeValue.attributeName)
- XCTAssertEqual(compositeValue.stops as NSDictionary, expectedStops as NSDictionary)
- XCTAssertEqual(compositeValue.interpolationMode, expectedCompositeValue.interpolationMode)
- XCTAssertEqual(compositeValue.defaultValue, expectedCompositeValue.defaultValue)
-
- // get a value back
- if let returnedCircleRadius = circleStyleLayer.circleRadius as? MGLCompositeStyleFunction<NSNumber> {
- if let returnedStops = returnedCircleRadius.stops as NSDictionary? as? [NSNumber: [NSNumber: MGLStyleValue<NSNumber>]] {
- let lhs: MGLStyleValue<NSNumber> = returnedStops[0]!.values.first!
- let rhs: MGLStyleValue<NSNumber> = radiusCompositeExponentialOrIntervalStops[0]!.values.first!
- XCTAssertEqual(lhs, rhs)
- }
- }
-
- // get value back as base class
- if let returnedCircleRadius = circleStyleLayer.circleRadius as? MGLStyleFunction<NSNumber> {
- if let returnedStops = returnedCircleRadius.stops as NSDictionary? as? [NSNumber: [NSNumber: MGLStyleValue<NSNumber>]] {
- let lhs: MGLStyleValue<NSNumber> = returnedStops[0]!.values.first!
- let rhs: MGLStyleValue<NSNumber> = radiusCompositeExponentialOrIntervalStops[0]!.values.first!
- XCTAssertEqual(lhs, rhs)
- }
- }
-
- // data-driven, composite function with inner interval color stop values nested in outer camera stops
- let expectedCompositeIntervalValue = MGLStyleValue<NSNumber>(
- interpolationMode: .interval,
- compositeStops: [
-
- 10: [200: MGLStyleValue<NSNumber>(rawValue: 5)],
- 20: [200: MGLStyleValue<NSNumber>(rawValue: 20)]
- ],
- attributeName: "temp",
- options: nil
- )
- circleStyleLayer.circleRadius = MGLStyleValue<NSNumber>(
- interpolationMode: .interval,
- compositeStops: [
- 0: [0: MGLStyleValue<NSNumber>(rawValue: 5)],
- 10: [200: MGLStyleValue<NSNumber>(rawValue: 5)],
- 20: [200: MGLStyleValue<NSNumber>(rawValue: 20)]
- ],
- attributeName: "temp",
- options: nil
- )
-
- compositeValue = circleStyleLayer.circleRadius as! MGLCompositeStyleFunction
- expectedCompositeValue = expectedCompositeIntervalValue as! MGLCompositeStyleFunction
- XCTAssertEqual(compositeValue.attributeName, expectedCompositeValue.attributeName)
- XCTAssertEqual(compositeValue.stops as NSDictionary, expectedStops as NSDictionary)
- XCTAssertEqual(compositeValue.interpolationMode, expectedCompositeValue.interpolationMode)
- XCTAssertEqual(compositeValue.defaultValue, expectedCompositeValue.defaultValue)
- }
-}
diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.mm b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
index 1ac86dd402..cf2f80125a 100644
--- a/platform/darwin/test/MGLSymbolStyleLayerTests.mm
+++ b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
@@ -30,8 +30,8 @@
XCTAssertNil(layer.sourceLayerIdentifier);
XCTAssertNil(layer.predicate);
- layer.predicate = [NSPredicate predicateWithValue:NO];
- XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
+ layer.predicate = [NSPredicate predicateWithFormat:@"$featureIdentifier = 1"];
+ XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithFormat:@"$featureIdentifier = 1"]);
layer.predicate = nil;
XCTAssertNil(layer.predicate);
}
@@ -52,72 +52,81 @@
{
XCTAssertTrue(rawLayer->getIconAllowOverlap().isUndefined(),
@"icon-allow-overlap should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconAllowsOverlap;
+ NSExpression *defaultExpression = layer.iconAllowsOverlap;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
- layer.iconAllowsOverlap = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"true"];
+ layer.iconAllowsOverlap = constantExpression;
mbgl::style::PropertyValue<bool> propertyValue = { true };
XCTAssertEqual(rawLayer->getIconAllowOverlap(), propertyValue,
- @"Setting iconAllowsOverlap to a constant value should update icon-allow-overlap.");
- XCTAssertEqualObjects(layer.iconAllowsOverlap, constantStyleValue,
- @"iconAllowsOverlap should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconAllowsOverlap = functionStyleValue;
-
- mbgl::style::IntervalStops<bool> intervalStops = { {{18, true}} };
+ @"Setting iconAllowsOverlap to a constant value expression should update icon-allow-overlap.");
+ XCTAssertEqualObjects(layer.iconAllowsOverlap, constantExpression,
+ @"iconAllowsOverlap should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"true"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconAllowsOverlap = functionExpression;
+
+ mbgl::style::IntervalStops<bool> intervalStops = {{
+ { -INFINITY, true },
+ { 18, true },
+ }};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
XCTAssertEqual(rawLayer->getIconAllowOverlap(), propertyValue,
- @"Setting iconAllowsOverlap to a camera function should update icon-allow-overlap.");
- XCTAssertEqualObjects(layer.iconAllowsOverlap, functionStyleValue,
- @"iconAllowsOverlap should round-trip camera functions.");
+ @"Setting iconAllowsOverlap to a camera expression should update icon-allow-overlap.");
+ XCTAssertEqualObjects(layer.iconAllowsOverlap, functionExpression,
+ @"iconAllowsOverlap should round-trip camera expressions.");
layer.iconAllowsOverlap = nil;
XCTAssertTrue(rawLayer->getIconAllowOverlap().isUndefined(),
@"Unsetting iconAllowsOverlap should return icon-allow-overlap to the default value.");
- XCTAssertEqualObjects(layer.iconAllowsOverlap, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconAllowsOverlap, defaultExpression,
@"iconAllowsOverlap should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconAllowsOverlap = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconAllowsOverlap = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.iconAllowsOverlap = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.iconAllowsOverlap = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// icon-anchor
{
XCTAssertTrue(rawLayer->getIconAnchor().isUndefined(),
@"icon-anchor should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconAnchor;
+ NSExpression *defaultExpression = layer.iconAnchor;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconAnchor:MGLIconAnchorBottomRight]];
- layer.iconAnchor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'bottom-right'"];
+ layer.iconAnchor = constantExpression;
mbgl::style::DataDrivenPropertyValue<mbgl::style::SymbolAnchorType> propertyValue = { mbgl::style::SymbolAnchorType::BottomRight };
XCTAssertEqual(rawLayer->getIconAnchor(), propertyValue,
- @"Setting iconAnchor to a constant value should update icon-anchor.");
- XCTAssertEqualObjects(layer.iconAnchor, constantStyleValue,
- @"iconAnchor should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconAnchor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::SymbolAnchorType> intervalStops = { {{18, mbgl::style::SymbolAnchorType::BottomRight}} };
+ @"Setting iconAnchor to a constant value expression should update icon-anchor.");
+ XCTAssertEqualObjects(layer.iconAnchor, constantExpression,
+ @"iconAnchor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'bottom-right'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconAnchor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::SymbolAnchorType> intervalStops = {{
+ { -INFINITY, mbgl::style::SymbolAnchorType::BottomRight },
+ { 18, mbgl::style::SymbolAnchorType::BottomRight },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::SymbolAnchorType> { intervalStops };
XCTAssertEqual(rawLayer->getIconAnchor(), propertyValue,
- @"Setting iconAnchor to a camera function should update icon-anchor.");
- XCTAssertEqualObjects(layer.iconAnchor, functionStyleValue,
- @"iconAnchor should round-trip camera functions.");
+ @"Setting iconAnchor to a camera expression should update icon-anchor.");
+ XCTAssertEqualObjects(layer.iconAnchor, functionExpression,
+ @"iconAnchor should round-trip camera expressions.");
layer.iconAnchor = nil;
XCTAssertTrue(rawLayer->getIconAnchor().isUndefined(),
@"Unsetting iconAnchor should return icon-anchor to the default value.");
- XCTAssertEqualObjects(layer.iconAnchor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconAnchor, defaultExpression,
@"iconAnchor should return the default value after being unset.");
}
@@ -125,72 +134,81 @@
{
XCTAssertTrue(rawLayer->getIconIgnorePlacement().isUndefined(),
@"icon-ignore-placement should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconIgnoresPlacement;
+ NSExpression *defaultExpression = layer.iconIgnoresPlacement;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
- layer.iconIgnoresPlacement = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"true"];
+ layer.iconIgnoresPlacement = constantExpression;
mbgl::style::PropertyValue<bool> propertyValue = { true };
XCTAssertEqual(rawLayer->getIconIgnorePlacement(), propertyValue,
- @"Setting iconIgnoresPlacement to a constant value should update icon-ignore-placement.");
- XCTAssertEqualObjects(layer.iconIgnoresPlacement, constantStyleValue,
- @"iconIgnoresPlacement should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconIgnoresPlacement = functionStyleValue;
-
- mbgl::style::IntervalStops<bool> intervalStops = { {{18, true}} };
+ @"Setting iconIgnoresPlacement to a constant value expression should update icon-ignore-placement.");
+ XCTAssertEqualObjects(layer.iconIgnoresPlacement, constantExpression,
+ @"iconIgnoresPlacement should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"true"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconIgnoresPlacement = functionExpression;
+
+ mbgl::style::IntervalStops<bool> intervalStops = {{
+ { -INFINITY, true },
+ { 18, true },
+ }};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
XCTAssertEqual(rawLayer->getIconIgnorePlacement(), propertyValue,
- @"Setting iconIgnoresPlacement to a camera function should update icon-ignore-placement.");
- XCTAssertEqualObjects(layer.iconIgnoresPlacement, functionStyleValue,
- @"iconIgnoresPlacement should round-trip camera functions.");
+ @"Setting iconIgnoresPlacement to a camera expression should update icon-ignore-placement.");
+ XCTAssertEqualObjects(layer.iconIgnoresPlacement, functionExpression,
+ @"iconIgnoresPlacement should round-trip camera expressions.");
layer.iconIgnoresPlacement = nil;
XCTAssertTrue(rawLayer->getIconIgnorePlacement().isUndefined(),
@"Unsetting iconIgnoresPlacement should return icon-ignore-placement to the default value.");
- XCTAssertEqualObjects(layer.iconIgnoresPlacement, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconIgnoresPlacement, defaultExpression,
@"iconIgnoresPlacement should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconIgnoresPlacement = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconIgnoresPlacement = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.iconIgnoresPlacement = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.iconIgnoresPlacement = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// icon-image
{
XCTAssertTrue(rawLayer->getIconImage().isUndefined(),
@"icon-image should be unset initially.");
- MGLStyleValue<NSString *> *defaultStyleValue = layer.iconImageName;
+ NSExpression *defaultExpression = layer.iconImageName;
- MGLStyleValue<NSString *> *constantStyleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Icon Image"];
- layer.iconImageName = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'Icon Image'"];
+ layer.iconImageName = constantExpression;
mbgl::style::DataDrivenPropertyValue<std::string> propertyValue = { "Icon Image" };
XCTAssertEqual(rawLayer->getIconImage(), propertyValue,
- @"Setting iconImageName to a constant value should update icon-image.");
- XCTAssertEqualObjects(layer.iconImageName, constantStyleValue,
- @"iconImageName should round-trip constant values.");
-
- MGLStyleValue<NSString *> * functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconImageName = functionStyleValue;
-
- mbgl::style::IntervalStops<std::string> intervalStops = { {{18, "Icon Image"}} };
+ @"Setting iconImageName to a constant value expression should update icon-image.");
+ XCTAssertEqualObjects(layer.iconImageName, constantExpression,
+ @"iconImageName should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'Icon Image'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconImageName = functionExpression;
+
+ mbgl::style::IntervalStops<std::string> intervalStops = {{
+ { -INFINITY, "Icon Image" },
+ { 18, "Icon Image" },
+ }};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
XCTAssertEqual(rawLayer->getIconImage(), propertyValue,
- @"Setting iconImageName to a camera function should update icon-image.");
- XCTAssertEqualObjects(layer.iconImageName, functionStyleValue,
- @"iconImageName should round-trip camera functions.");
+ @"Setting iconImageName to a camera expression should update icon-image.");
+ XCTAssertEqualObjects(layer.iconImageName, functionExpression,
+ @"iconImageName should round-trip camera expressions.");
layer.iconImageName = nil;
XCTAssertTrue(rawLayer->getIconImage().isUndefined(),
@"Unsetting iconImageName should return icon-image to the default value.");
- XCTAssertEqualObjects(layer.iconImageName, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconImageName, defaultExpression,
@"iconImageName should return the default value after being unset.");
}
@@ -198,46 +216,51 @@
{
XCTAssertTrue(rawLayer->getIconOffset().isUndefined(),
@"icon-offset should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconOffset;
+ NSExpression *defaultExpression = layer.iconOffset;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@",
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
- layer.iconOffset = constantStyleValue;
+ layer.iconOffset = constantExpression;
mbgl::style::DataDrivenPropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getIconOffset(), propertyValue,
- @"Setting iconOffset to a constant value should update icon-offset.");
- XCTAssertEqualObjects(layer.iconOffset, constantStyleValue,
- @"iconOffset should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconOffset = functionStyleValue;
-
- mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} };
+ @"Setting iconOffset to a constant value expression should update icon-offset.");
+ XCTAssertEqualObjects(layer.iconOffset, constantExpression,
+ @"iconOffset should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"{1, 1}"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconOffset = functionExpression;
+
+ mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = {{
+ { -INFINITY, { 1, 1 } },
+ { 18, { 1, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
XCTAssertEqual(rawLayer->getIconOffset(), propertyValue,
- @"Setting iconOffset to a camera function should update icon-offset.");
- XCTAssertEqualObjects(layer.iconOffset, functionStyleValue,
- @"iconOffset should round-trip camera functions.");
+ @"Setting iconOffset to a camera expression should update icon-offset.");
+ XCTAssertEqualObjects(layer.iconOffset, functionExpression,
+ @"iconOffset should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.iconOffset = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.iconOffset = functionExpression;
mbgl::style::ExponentialStops<std::array<float, 2>> exponentialStops = { {{18, { 1, 1 }}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<std::array<float, 2>> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getIconOffset(), propertyValue,
- @"Setting iconOffset to a source function should update icon-offset.");
- XCTAssertEqualObjects(layer.iconOffset, functionStyleValue,
- @"iconOffset should round-trip source functions.");
+ @"Setting iconOffset to a data expression should update icon-offset.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.iconOffset, pedanticFunctionExpression,
+ @"iconOffset should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.iconOffset = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.iconOffset = functionExpression;
std::map<float, std::array<float, 2>> innerStops { {18, { 1, 1 }} };
mbgl::style::CompositeExponentialStops<std::array<float, 2>> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -245,15 +268,16 @@
propertyValue = mbgl::style::CompositeFunction<std::array<float, 2>> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getIconOffset(), propertyValue,
- @"Setting iconOffset to a composite function should update icon-offset.");
- XCTAssertEqualObjects(layer.iconOffset, functionStyleValue,
- @"iconOffset should round-trip composite functions.");
+ @"Setting iconOffset to a camera-data expression should update icon-offset.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.iconOffset, pedanticFunctionExpression,
+ @"iconOffset should round-trip camera-data expressions.");
layer.iconOffset = nil;
XCTAssertTrue(rawLayer->getIconOffset().isUndefined(),
@"Unsetting iconOffset should return icon-offset to the default value.");
- XCTAssertEqualObjects(layer.iconOffset, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconOffset, defaultExpression,
@"iconOffset should return the default value after being unset.");
}
@@ -261,157 +285,177 @@
{
XCTAssertTrue(rawLayer->getIconOptional().isUndefined(),
@"icon-optional should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconOptional;
+ NSExpression *defaultExpression = layer.iconOptional;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
- layer.iconOptional = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"true"];
+ layer.iconOptional = constantExpression;
mbgl::style::PropertyValue<bool> propertyValue = { true };
XCTAssertEqual(rawLayer->getIconOptional(), propertyValue,
- @"Setting iconOptional to a constant value should update icon-optional.");
- XCTAssertEqualObjects(layer.iconOptional, constantStyleValue,
- @"iconOptional should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconOptional = functionStyleValue;
-
- mbgl::style::IntervalStops<bool> intervalStops = { {{18, true}} };
+ @"Setting iconOptional to a constant value expression should update icon-optional.");
+ XCTAssertEqualObjects(layer.iconOptional, constantExpression,
+ @"iconOptional should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"true"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconOptional = functionExpression;
+
+ mbgl::style::IntervalStops<bool> intervalStops = {{
+ { -INFINITY, true },
+ { 18, true },
+ }};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
XCTAssertEqual(rawLayer->getIconOptional(), propertyValue,
- @"Setting iconOptional to a camera function should update icon-optional.");
- XCTAssertEqualObjects(layer.iconOptional, functionStyleValue,
- @"iconOptional should round-trip camera functions.");
+ @"Setting iconOptional to a camera expression should update icon-optional.");
+ XCTAssertEqualObjects(layer.iconOptional, functionExpression,
+ @"iconOptional should round-trip camera expressions.");
layer.iconOptional = nil;
XCTAssertTrue(rawLayer->getIconOptional().isUndefined(),
@"Unsetting iconOptional should return icon-optional to the default value.");
- XCTAssertEqualObjects(layer.iconOptional, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconOptional, defaultExpression,
@"iconOptional should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconOptional = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconOptional = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.iconOptional = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.iconOptional = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// icon-padding
{
XCTAssertTrue(rawLayer->getIconPadding().isUndefined(),
@"icon-padding should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconPadding;
+ NSExpression *defaultExpression = layer.iconPadding;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.iconPadding = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.iconPadding = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconPadding(), propertyValue,
- @"Setting iconPadding to a constant value should update icon-padding.");
- XCTAssertEqualObjects(layer.iconPadding, constantStyleValue,
- @"iconPadding should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconPadding = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting iconPadding to a constant value expression should update icon-padding.");
+ XCTAssertEqualObjects(layer.iconPadding, constantExpression,
+ @"iconPadding should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconPadding = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getIconPadding(), propertyValue,
- @"Setting iconPadding to a camera function should update icon-padding.");
- XCTAssertEqualObjects(layer.iconPadding, functionStyleValue,
- @"iconPadding should round-trip camera functions.");
+ @"Setting iconPadding to a camera expression should update icon-padding.");
+ XCTAssertEqualObjects(layer.iconPadding, functionExpression,
+ @"iconPadding should round-trip camera expressions.");
layer.iconPadding = nil;
XCTAssertTrue(rawLayer->getIconPadding().isUndefined(),
@"Unsetting iconPadding should return icon-padding to the default value.");
- XCTAssertEqualObjects(layer.iconPadding, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconPadding, defaultExpression,
@"iconPadding should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconPadding = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconPadding = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.iconPadding = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.iconPadding = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// icon-pitch-alignment
{
XCTAssertTrue(rawLayer->getIconPitchAlignment().isUndefined(),
@"icon-pitch-alignment should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconPitchAlignment;
+ NSExpression *defaultExpression = layer.iconPitchAlignment;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconPitchAlignment:MGLIconPitchAlignmentAuto]];
- layer.iconPitchAlignment = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'auto'"];
+ layer.iconPitchAlignment = constantExpression;
mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Auto };
XCTAssertEqual(rawLayer->getIconPitchAlignment(), propertyValue,
- @"Setting iconPitchAlignment to a constant value should update icon-pitch-alignment.");
- XCTAssertEqualObjects(layer.iconPitchAlignment, constantStyleValue,
- @"iconPitchAlignment should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconPitchAlignment = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = { {{18, mbgl::style::AlignmentType::Auto}} };
+ @"Setting iconPitchAlignment to a constant value expression should update icon-pitch-alignment.");
+ XCTAssertEqualObjects(layer.iconPitchAlignment, constantExpression,
+ @"iconPitchAlignment should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'auto'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconPitchAlignment = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = {{
+ { -INFINITY, mbgl::style::AlignmentType::Auto },
+ { 18, mbgl::style::AlignmentType::Auto },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
XCTAssertEqual(rawLayer->getIconPitchAlignment(), propertyValue,
- @"Setting iconPitchAlignment to a camera function should update icon-pitch-alignment.");
- XCTAssertEqualObjects(layer.iconPitchAlignment, functionStyleValue,
- @"iconPitchAlignment should round-trip camera functions.");
+ @"Setting iconPitchAlignment to a camera expression should update icon-pitch-alignment.");
+ XCTAssertEqualObjects(layer.iconPitchAlignment, functionExpression,
+ @"iconPitchAlignment should round-trip camera expressions.");
layer.iconPitchAlignment = nil;
XCTAssertTrue(rawLayer->getIconPitchAlignment().isUndefined(),
@"Unsetting iconPitchAlignment should return icon-pitch-alignment to the default value.");
- XCTAssertEqualObjects(layer.iconPitchAlignment, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconPitchAlignment, defaultExpression,
@"iconPitchAlignment should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconPitchAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconPitchAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.iconPitchAlignment = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.iconPitchAlignment = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// icon-rotate
{
XCTAssertTrue(rawLayer->getIconRotate().isUndefined(),
@"icon-rotate should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconRotation;
+ NSExpression *defaultExpression = layer.iconRotation;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.iconRotation = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.iconRotation = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconRotate(), propertyValue,
- @"Setting iconRotation to a constant value should update icon-rotate.");
- XCTAssertEqualObjects(layer.iconRotation, constantStyleValue,
- @"iconRotation should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconRotation = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting iconRotation to a constant value expression should update icon-rotate.");
+ XCTAssertEqualObjects(layer.iconRotation, constantExpression,
+ @"iconRotation should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconRotation = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getIconRotate(), propertyValue,
- @"Setting iconRotation to a camera function should update icon-rotate.");
- XCTAssertEqualObjects(layer.iconRotation, functionStyleValue,
- @"iconRotation should round-trip camera functions.");
+ @"Setting iconRotation to a camera expression should update icon-rotate.");
+ XCTAssertEqualObjects(layer.iconRotation, functionExpression,
+ @"iconRotation should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.iconRotation = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.iconRotation = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getIconRotate(), propertyValue,
- @"Setting iconRotation to a source function should update icon-rotate.");
- XCTAssertEqualObjects(layer.iconRotation, functionStyleValue,
- @"iconRotation should round-trip source functions.");
+ @"Setting iconRotation to a data expression should update icon-rotate.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.iconRotation, pedanticFunctionExpression,
+ @"iconRotation should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.iconRotation = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.iconRotation = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -419,15 +463,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getIconRotate(), propertyValue,
- @"Setting iconRotation to a composite function should update icon-rotate.");
- XCTAssertEqualObjects(layer.iconRotation, functionStyleValue,
- @"iconRotation should round-trip composite functions.");
+ @"Setting iconRotation to a camera-data expression should update icon-rotate.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.iconRotation, pedanticFunctionExpression,
+ @"iconRotation should round-trip camera-data expressions.");
layer.iconRotation = nil;
XCTAssertTrue(rawLayer->getIconRotate().isUndefined(),
@"Unsetting iconRotation should return icon-rotate to the default value.");
- XCTAssertEqualObjects(layer.iconRotation, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconRotation, defaultExpression,
@"iconRotation should return the default value after being unset.");
}
@@ -435,79 +480,89 @@
{
XCTAssertTrue(rawLayer->getIconRotationAlignment().isUndefined(),
@"icon-rotation-alignment should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconRotationAlignment;
+ NSExpression *defaultExpression = layer.iconRotationAlignment;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentAuto]];
- layer.iconRotationAlignment = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'auto'"];
+ layer.iconRotationAlignment = constantExpression;
mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Auto };
XCTAssertEqual(rawLayer->getIconRotationAlignment(), propertyValue,
- @"Setting iconRotationAlignment to a constant value should update icon-rotation-alignment.");
- XCTAssertEqualObjects(layer.iconRotationAlignment, constantStyleValue,
- @"iconRotationAlignment should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconRotationAlignment = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = { {{18, mbgl::style::AlignmentType::Auto}} };
+ @"Setting iconRotationAlignment to a constant value expression should update icon-rotation-alignment.");
+ XCTAssertEqualObjects(layer.iconRotationAlignment, constantExpression,
+ @"iconRotationAlignment should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'auto'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconRotationAlignment = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = {{
+ { -INFINITY, mbgl::style::AlignmentType::Auto },
+ { 18, mbgl::style::AlignmentType::Auto },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
XCTAssertEqual(rawLayer->getIconRotationAlignment(), propertyValue,
- @"Setting iconRotationAlignment to a camera function should update icon-rotation-alignment.");
- XCTAssertEqualObjects(layer.iconRotationAlignment, functionStyleValue,
- @"iconRotationAlignment should round-trip camera functions.");
+ @"Setting iconRotationAlignment to a camera expression should update icon-rotation-alignment.");
+ XCTAssertEqualObjects(layer.iconRotationAlignment, functionExpression,
+ @"iconRotationAlignment should round-trip camera expressions.");
layer.iconRotationAlignment = nil;
XCTAssertTrue(rawLayer->getIconRotationAlignment().isUndefined(),
@"Unsetting iconRotationAlignment should return icon-rotation-alignment to the default value.");
- XCTAssertEqualObjects(layer.iconRotationAlignment, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconRotationAlignment, defaultExpression,
@"iconRotationAlignment should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconRotationAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconRotationAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.iconRotationAlignment = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.iconRotationAlignment = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// icon-size
{
XCTAssertTrue(rawLayer->getIconSize().isUndefined(),
@"icon-size should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconScale;
+ NSExpression *defaultExpression = layer.iconScale;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.iconScale = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.iconScale = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconSize(), propertyValue,
- @"Setting iconScale to a constant value should update icon-size.");
- XCTAssertEqualObjects(layer.iconScale, constantStyleValue,
- @"iconScale should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconScale = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting iconScale to a constant value expression should update icon-size.");
+ XCTAssertEqualObjects(layer.iconScale, constantExpression,
+ @"iconScale should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconScale = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getIconSize(), propertyValue,
- @"Setting iconScale to a camera function should update icon-size.");
- XCTAssertEqualObjects(layer.iconScale, functionStyleValue,
- @"iconScale should round-trip camera functions.");
+ @"Setting iconScale to a camera expression should update icon-size.");
+ XCTAssertEqualObjects(layer.iconScale, functionExpression,
+ @"iconScale should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.iconScale = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.iconScale = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getIconSize(), propertyValue,
- @"Setting iconScale to a source function should update icon-size.");
- XCTAssertEqualObjects(layer.iconScale, functionStyleValue,
- @"iconScale should round-trip source functions.");
+ @"Setting iconScale to a data expression should update icon-size.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.iconScale, pedanticFunctionExpression,
+ @"iconScale should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.iconScale = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.iconScale = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -515,15 +570,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getIconSize(), propertyValue,
- @"Setting iconScale to a composite function should update icon-size.");
- XCTAssertEqualObjects(layer.iconScale, functionStyleValue,
- @"iconScale should round-trip composite functions.");
+ @"Setting iconScale to a camera-data expression should update icon-size.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.iconScale, pedanticFunctionExpression,
+ @"iconScale should round-trip camera-data expressions.");
layer.iconScale = nil;
XCTAssertTrue(rawLayer->getIconSize().isUndefined(),
@"Unsetting iconScale should return icon-size to the default value.");
- XCTAssertEqualObjects(layer.iconScale, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconScale, defaultExpression,
@"iconScale should return the default value after being unset.");
}
@@ -531,241 +587,271 @@
{
XCTAssertTrue(rawLayer->getIconTextFit().isUndefined(),
@"icon-text-fit should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconTextFit;
+ NSExpression *defaultExpression = layer.iconTextFit;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconTextFit:MGLIconTextFitBoth]];
- layer.iconTextFit = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'both'"];
+ layer.iconTextFit = constantExpression;
mbgl::style::PropertyValue<mbgl::style::IconTextFitType> propertyValue = { mbgl::style::IconTextFitType::Both };
XCTAssertEqual(rawLayer->getIconTextFit(), propertyValue,
- @"Setting iconTextFit to a constant value should update icon-text-fit.");
- XCTAssertEqualObjects(layer.iconTextFit, constantStyleValue,
- @"iconTextFit should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconTextFit = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::IconTextFitType> intervalStops = { {{18, mbgl::style::IconTextFitType::Both}} };
+ @"Setting iconTextFit to a constant value expression should update icon-text-fit.");
+ XCTAssertEqualObjects(layer.iconTextFit, constantExpression,
+ @"iconTextFit should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'both'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconTextFit = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::IconTextFitType> intervalStops = {{
+ { -INFINITY, mbgl::style::IconTextFitType::Both },
+ { 18, mbgl::style::IconTextFitType::Both },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::IconTextFitType> { intervalStops };
XCTAssertEqual(rawLayer->getIconTextFit(), propertyValue,
- @"Setting iconTextFit to a camera function should update icon-text-fit.");
- XCTAssertEqualObjects(layer.iconTextFit, functionStyleValue,
- @"iconTextFit should round-trip camera functions.");
+ @"Setting iconTextFit to a camera expression should update icon-text-fit.");
+ XCTAssertEqualObjects(layer.iconTextFit, functionExpression,
+ @"iconTextFit should round-trip camera expressions.");
layer.iconTextFit = nil;
XCTAssertTrue(rawLayer->getIconTextFit().isUndefined(),
@"Unsetting iconTextFit should return icon-text-fit to the default value.");
- XCTAssertEqualObjects(layer.iconTextFit, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconTextFit, defaultExpression,
@"iconTextFit should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconTextFit = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconTextFit = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.iconTextFit = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.iconTextFit = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// icon-text-fit-padding
{
XCTAssertTrue(rawLayer->getIconTextFitPadding().isUndefined(),
@"icon-text-fit-padding should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconTextFitPadding;
+ NSExpression *defaultExpression = layer.iconTextFitPadding;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@",
#if TARGET_OS_IPHONE
[NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(1, 1, 1, 1)]
#else
[NSValue valueWithEdgeInsets:NSEdgeInsetsMake(1, 1, 1, 1)]
#endif
];
- layer.iconTextFitPadding = constantStyleValue;
+ layer.iconTextFitPadding = constantExpression;
mbgl::style::PropertyValue<std::array<float, 4>> propertyValue = { { 1, 1, 1, 1 } };
XCTAssertEqual(rawLayer->getIconTextFitPadding(), propertyValue,
- @"Setting iconTextFitPadding to a constant value should update icon-text-fit-padding.");
- XCTAssertEqualObjects(layer.iconTextFitPadding, constantStyleValue,
- @"iconTextFitPadding should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconTextFitPadding = functionStyleValue;
-
- mbgl::style::IntervalStops<std::array<float, 4>> intervalStops = { {{18, { 1, 1, 1, 1 }}} };
+ @"Setting iconTextFitPadding to a constant value expression should update icon-text-fit-padding.");
+ XCTAssertEqualObjects(layer.iconTextFitPadding, constantExpression,
+ @"iconTextFitPadding should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"{1, 1, 1, 1}"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconTextFitPadding = functionExpression;
+
+ mbgl::style::IntervalStops<std::array<float, 4>> intervalStops = {{
+ { -INFINITY, { 1, 1, 1, 1 } },
+ { 18, { 1, 1, 1, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<std::array<float, 4>> { intervalStops };
XCTAssertEqual(rawLayer->getIconTextFitPadding(), propertyValue,
- @"Setting iconTextFitPadding to a camera function should update icon-text-fit-padding.");
- XCTAssertEqualObjects(layer.iconTextFitPadding, functionStyleValue,
- @"iconTextFitPadding should round-trip camera functions.");
+ @"Setting iconTextFitPadding to a camera expression should update icon-text-fit-padding.");
+ XCTAssertEqualObjects(layer.iconTextFitPadding, functionExpression,
+ @"iconTextFitPadding should round-trip camera expressions.");
layer.iconTextFitPadding = nil;
XCTAssertTrue(rawLayer->getIconTextFitPadding().isUndefined(),
@"Unsetting iconTextFitPadding should return icon-text-fit-padding to the default value.");
- XCTAssertEqualObjects(layer.iconTextFitPadding, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconTextFitPadding, defaultExpression,
@"iconTextFitPadding should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconTextFitPadding = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconTextFitPadding = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.iconTextFitPadding = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.iconTextFitPadding = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// icon-keep-upright
{
XCTAssertTrue(rawLayer->getIconKeepUpright().isUndefined(),
@"icon-keep-upright should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.keepsIconUpright;
+ NSExpression *defaultExpression = layer.keepsIconUpright;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
- layer.keepsIconUpright = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"true"];
+ layer.keepsIconUpright = constantExpression;
mbgl::style::PropertyValue<bool> propertyValue = { true };
XCTAssertEqual(rawLayer->getIconKeepUpright(), propertyValue,
- @"Setting keepsIconUpright to a constant value should update icon-keep-upright.");
- XCTAssertEqualObjects(layer.keepsIconUpright, constantStyleValue,
- @"keepsIconUpright should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.keepsIconUpright = functionStyleValue;
-
- mbgl::style::IntervalStops<bool> intervalStops = { {{18, true}} };
+ @"Setting keepsIconUpright to a constant value expression should update icon-keep-upright.");
+ XCTAssertEqualObjects(layer.keepsIconUpright, constantExpression,
+ @"keepsIconUpright should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"true"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.keepsIconUpright = functionExpression;
+
+ mbgl::style::IntervalStops<bool> intervalStops = {{
+ { -INFINITY, true },
+ { 18, true },
+ }};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
XCTAssertEqual(rawLayer->getIconKeepUpright(), propertyValue,
- @"Setting keepsIconUpright to a camera function should update icon-keep-upright.");
- XCTAssertEqualObjects(layer.keepsIconUpright, functionStyleValue,
- @"keepsIconUpright should round-trip camera functions.");
+ @"Setting keepsIconUpright to a camera expression should update icon-keep-upright.");
+ XCTAssertEqualObjects(layer.keepsIconUpright, functionExpression,
+ @"keepsIconUpright should round-trip camera expressions.");
layer.keepsIconUpright = nil;
XCTAssertTrue(rawLayer->getIconKeepUpright().isUndefined(),
@"Unsetting keepsIconUpright should return icon-keep-upright to the default value.");
- XCTAssertEqualObjects(layer.keepsIconUpright, defaultStyleValue,
+ XCTAssertEqualObjects(layer.keepsIconUpright, defaultExpression,
@"keepsIconUpright should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.keepsIconUpright = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.keepsIconUpright = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.keepsIconUpright = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.keepsIconUpright = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// text-keep-upright
{
XCTAssertTrue(rawLayer->getTextKeepUpright().isUndefined(),
@"text-keep-upright should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.keepsTextUpright;
+ NSExpression *defaultExpression = layer.keepsTextUpright;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@NO];
- layer.keepsTextUpright = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"false"];
+ layer.keepsTextUpright = constantExpression;
mbgl::style::PropertyValue<bool> propertyValue = { false };
XCTAssertEqual(rawLayer->getTextKeepUpright(), propertyValue,
- @"Setting keepsTextUpright to a constant value should update text-keep-upright.");
- XCTAssertEqualObjects(layer.keepsTextUpright, constantStyleValue,
- @"keepsTextUpright should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.keepsTextUpright = functionStyleValue;
-
- mbgl::style::IntervalStops<bool> intervalStops = { {{18, false}} };
+ @"Setting keepsTextUpright to a constant value expression should update text-keep-upright.");
+ XCTAssertEqualObjects(layer.keepsTextUpright, constantExpression,
+ @"keepsTextUpright should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"false"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.keepsTextUpright = functionExpression;
+
+ mbgl::style::IntervalStops<bool> intervalStops = {{
+ { -INFINITY, false },
+ { 18, false },
+ }};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
XCTAssertEqual(rawLayer->getTextKeepUpright(), propertyValue,
- @"Setting keepsTextUpright to a camera function should update text-keep-upright.");
- XCTAssertEqualObjects(layer.keepsTextUpright, functionStyleValue,
- @"keepsTextUpright should round-trip camera functions.");
+ @"Setting keepsTextUpright to a camera expression should update text-keep-upright.");
+ XCTAssertEqualObjects(layer.keepsTextUpright, functionExpression,
+ @"keepsTextUpright should round-trip camera expressions.");
layer.keepsTextUpright = nil;
XCTAssertTrue(rawLayer->getTextKeepUpright().isUndefined(),
@"Unsetting keepsTextUpright should return text-keep-upright to the default value.");
- XCTAssertEqualObjects(layer.keepsTextUpright, defaultStyleValue,
+ XCTAssertEqualObjects(layer.keepsTextUpright, defaultExpression,
@"keepsTextUpright should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.keepsTextUpright = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.keepsTextUpright = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.keepsTextUpright = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.keepsTextUpright = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// text-max-angle
{
XCTAssertTrue(rawLayer->getTextMaxAngle().isUndefined(),
@"text-max-angle should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.maximumTextAngle;
+ NSExpression *defaultExpression = layer.maximumTextAngle;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.maximumTextAngle = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.maximumTextAngle = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextMaxAngle(), propertyValue,
- @"Setting maximumTextAngle to a constant value should update text-max-angle.");
- XCTAssertEqualObjects(layer.maximumTextAngle, constantStyleValue,
- @"maximumTextAngle should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.maximumTextAngle = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting maximumTextAngle to a constant value expression should update text-max-angle.");
+ XCTAssertEqualObjects(layer.maximumTextAngle, constantExpression,
+ @"maximumTextAngle should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.maximumTextAngle = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getTextMaxAngle(), propertyValue,
- @"Setting maximumTextAngle to a camera function should update text-max-angle.");
- XCTAssertEqualObjects(layer.maximumTextAngle, functionStyleValue,
- @"maximumTextAngle should round-trip camera functions.");
+ @"Setting maximumTextAngle to a camera expression should update text-max-angle.");
+ XCTAssertEqualObjects(layer.maximumTextAngle, functionExpression,
+ @"maximumTextAngle should round-trip camera expressions.");
layer.maximumTextAngle = nil;
XCTAssertTrue(rawLayer->getTextMaxAngle().isUndefined(),
@"Unsetting maximumTextAngle should return text-max-angle to the default value.");
- XCTAssertEqualObjects(layer.maximumTextAngle, defaultStyleValue,
+ XCTAssertEqualObjects(layer.maximumTextAngle, defaultExpression,
@"maximumTextAngle should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.maximumTextAngle = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.maximumTextAngle = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.maximumTextAngle = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.maximumTextAngle = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// text-max-width
{
XCTAssertTrue(rawLayer->getTextMaxWidth().isUndefined(),
@"text-max-width should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.maximumTextWidth;
+ NSExpression *defaultExpression = layer.maximumTextWidth;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.maximumTextWidth = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.maximumTextWidth = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue,
- @"Setting maximumTextWidth to a constant value should update text-max-width.");
- XCTAssertEqualObjects(layer.maximumTextWidth, constantStyleValue,
- @"maximumTextWidth should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.maximumTextWidth = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting maximumTextWidth to a constant value expression should update text-max-width.");
+ XCTAssertEqualObjects(layer.maximumTextWidth, constantExpression,
+ @"maximumTextWidth should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.maximumTextWidth = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue,
- @"Setting maximumTextWidth to a camera function should update text-max-width.");
- XCTAssertEqualObjects(layer.maximumTextWidth, functionStyleValue,
- @"maximumTextWidth should round-trip camera functions.");
+ @"Setting maximumTextWidth to a camera expression should update text-max-width.");
+ XCTAssertEqualObjects(layer.maximumTextWidth, functionExpression,
+ @"maximumTextWidth should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.maximumTextWidth = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.maximumTextWidth = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue,
- @"Setting maximumTextWidth to a source function should update text-max-width.");
- XCTAssertEqualObjects(layer.maximumTextWidth, functionStyleValue,
- @"maximumTextWidth should round-trip source functions.");
+ @"Setting maximumTextWidth to a data expression should update text-max-width.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.maximumTextWidth, pedanticFunctionExpression,
+ @"maximumTextWidth should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.maximumTextWidth = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.maximumTextWidth = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -773,15 +859,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue,
- @"Setting maximumTextWidth to a composite function should update text-max-width.");
- XCTAssertEqualObjects(layer.maximumTextWidth, functionStyleValue,
- @"maximumTextWidth should round-trip composite functions.");
+ @"Setting maximumTextWidth to a camera-data expression should update text-max-width.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.maximumTextWidth, pedanticFunctionExpression,
+ @"maximumTextWidth should round-trip camera-data expressions.");
layer.maximumTextWidth = nil;
XCTAssertTrue(rawLayer->getTextMaxWidth().isUndefined(),
@"Unsetting maximumTextWidth should return text-max-width to the default value.");
- XCTAssertEqualObjects(layer.maximumTextWidth, defaultStyleValue,
+ XCTAssertEqualObjects(layer.maximumTextWidth, defaultExpression,
@"maximumTextWidth should return the default value after being unset.");
}
@@ -789,150 +876,169 @@
{
XCTAssertTrue(rawLayer->getSymbolAvoidEdges().isUndefined(),
@"symbol-avoid-edges should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.symbolAvoidsEdges;
+ NSExpression *defaultExpression = layer.symbolAvoidsEdges;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
- layer.symbolAvoidsEdges = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"true"];
+ layer.symbolAvoidsEdges = constantExpression;
mbgl::style::PropertyValue<bool> propertyValue = { true };
XCTAssertEqual(rawLayer->getSymbolAvoidEdges(), propertyValue,
- @"Setting symbolAvoidsEdges to a constant value should update symbol-avoid-edges.");
- XCTAssertEqualObjects(layer.symbolAvoidsEdges, constantStyleValue,
- @"symbolAvoidsEdges should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.symbolAvoidsEdges = functionStyleValue;
-
- mbgl::style::IntervalStops<bool> intervalStops = { {{18, true}} };
+ @"Setting symbolAvoidsEdges to a constant value expression should update symbol-avoid-edges.");
+ XCTAssertEqualObjects(layer.symbolAvoidsEdges, constantExpression,
+ @"symbolAvoidsEdges should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"true"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.symbolAvoidsEdges = functionExpression;
+
+ mbgl::style::IntervalStops<bool> intervalStops = {{
+ { -INFINITY, true },
+ { 18, true },
+ }};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
XCTAssertEqual(rawLayer->getSymbolAvoidEdges(), propertyValue,
- @"Setting symbolAvoidsEdges to a camera function should update symbol-avoid-edges.");
- XCTAssertEqualObjects(layer.symbolAvoidsEdges, functionStyleValue,
- @"symbolAvoidsEdges should round-trip camera functions.");
+ @"Setting symbolAvoidsEdges to a camera expression should update symbol-avoid-edges.");
+ XCTAssertEqualObjects(layer.symbolAvoidsEdges, functionExpression,
+ @"symbolAvoidsEdges should round-trip camera expressions.");
layer.symbolAvoidsEdges = nil;
XCTAssertTrue(rawLayer->getSymbolAvoidEdges().isUndefined(),
@"Unsetting symbolAvoidsEdges should return symbol-avoid-edges to the default value.");
- XCTAssertEqualObjects(layer.symbolAvoidsEdges, defaultStyleValue,
+ XCTAssertEqualObjects(layer.symbolAvoidsEdges, defaultExpression,
@"symbolAvoidsEdges should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.symbolAvoidsEdges = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.symbolAvoidsEdges = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.symbolAvoidsEdges = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.symbolAvoidsEdges = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// symbol-placement
{
XCTAssertTrue(rawLayer->getSymbolPlacement().isUndefined(),
@"symbol-placement should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.symbolPlacement;
+ NSExpression *defaultExpression = layer.symbolPlacement;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLSymbolPlacement:MGLSymbolPlacementLine]];
- layer.symbolPlacement = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'line'"];
+ layer.symbolPlacement = constantExpression;
mbgl::style::PropertyValue<mbgl::style::SymbolPlacementType> propertyValue = { mbgl::style::SymbolPlacementType::Line };
XCTAssertEqual(rawLayer->getSymbolPlacement(), propertyValue,
- @"Setting symbolPlacement to a constant value should update symbol-placement.");
- XCTAssertEqualObjects(layer.symbolPlacement, constantStyleValue,
- @"symbolPlacement should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.symbolPlacement = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::SymbolPlacementType> intervalStops = { {{18, mbgl::style::SymbolPlacementType::Line}} };
+ @"Setting symbolPlacement to a constant value expression should update symbol-placement.");
+ XCTAssertEqualObjects(layer.symbolPlacement, constantExpression,
+ @"symbolPlacement should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'line'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.symbolPlacement = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::SymbolPlacementType> intervalStops = {{
+ { -INFINITY, mbgl::style::SymbolPlacementType::Line },
+ { 18, mbgl::style::SymbolPlacementType::Line },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::SymbolPlacementType> { intervalStops };
XCTAssertEqual(rawLayer->getSymbolPlacement(), propertyValue,
- @"Setting symbolPlacement to a camera function should update symbol-placement.");
- XCTAssertEqualObjects(layer.symbolPlacement, functionStyleValue,
- @"symbolPlacement should round-trip camera functions.");
+ @"Setting symbolPlacement to a camera expression should update symbol-placement.");
+ XCTAssertEqualObjects(layer.symbolPlacement, functionExpression,
+ @"symbolPlacement should round-trip camera expressions.");
layer.symbolPlacement = nil;
XCTAssertTrue(rawLayer->getSymbolPlacement().isUndefined(),
@"Unsetting symbolPlacement should return symbol-placement to the default value.");
- XCTAssertEqualObjects(layer.symbolPlacement, defaultStyleValue,
+ XCTAssertEqualObjects(layer.symbolPlacement, defaultExpression,
@"symbolPlacement should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.symbolPlacement = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.symbolPlacement = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.symbolPlacement = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.symbolPlacement = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// symbol-spacing
{
XCTAssertTrue(rawLayer->getSymbolSpacing().isUndefined(),
@"symbol-spacing should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.symbolSpacing;
+ NSExpression *defaultExpression = layer.symbolSpacing;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.symbolSpacing = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.symbolSpacing = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getSymbolSpacing(), propertyValue,
- @"Setting symbolSpacing to a constant value should update symbol-spacing.");
- XCTAssertEqualObjects(layer.symbolSpacing, constantStyleValue,
- @"symbolSpacing should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.symbolSpacing = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting symbolSpacing to a constant value expression should update symbol-spacing.");
+ XCTAssertEqualObjects(layer.symbolSpacing, constantExpression,
+ @"symbolSpacing should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.symbolSpacing = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getSymbolSpacing(), propertyValue,
- @"Setting symbolSpacing to a camera function should update symbol-spacing.");
- XCTAssertEqualObjects(layer.symbolSpacing, functionStyleValue,
- @"symbolSpacing should round-trip camera functions.");
+ @"Setting symbolSpacing to a camera expression should update symbol-spacing.");
+ XCTAssertEqualObjects(layer.symbolSpacing, functionExpression,
+ @"symbolSpacing should round-trip camera expressions.");
layer.symbolSpacing = nil;
XCTAssertTrue(rawLayer->getSymbolSpacing().isUndefined(),
@"Unsetting symbolSpacing should return symbol-spacing to the default value.");
- XCTAssertEqualObjects(layer.symbolSpacing, defaultStyleValue,
+ XCTAssertEqualObjects(layer.symbolSpacing, defaultExpression,
@"symbolSpacing should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.symbolSpacing = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.symbolSpacing = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.symbolSpacing = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.symbolSpacing = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// text-field
{
XCTAssertTrue(rawLayer->getTextField().isUndefined(),
@"text-field should be unset initially.");
- MGLStyleValue<NSString *> *defaultStyleValue = layer.text;
+ NSExpression *defaultExpression = layer.text;
- MGLStyleValue<NSString *> *constantStyleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Text Field"];
- layer.text = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'Text Field'"];
+ layer.text = constantExpression;
mbgl::style::DataDrivenPropertyValue<std::string> propertyValue = { "Text Field" };
XCTAssertEqual(rawLayer->getTextField(), propertyValue,
- @"Setting text to a constant value should update text-field.");
- XCTAssertEqualObjects(layer.text, constantStyleValue,
- @"text should round-trip constant values.");
-
- MGLStyleValue<NSString *> * functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.text = functionStyleValue;
-
- mbgl::style::IntervalStops<std::string> intervalStops = { {{18, "Text Field"}} };
+ @"Setting text to a constant value expression should update text-field.");
+ XCTAssertEqualObjects(layer.text, constantExpression,
+ @"text should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'Text Field'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.text = functionExpression;
+
+ mbgl::style::IntervalStops<std::string> intervalStops = {{
+ { -INFINITY, "Text Field" },
+ { 18, "Text Field" },
+ }};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
XCTAssertEqual(rawLayer->getTextField(), propertyValue,
- @"Setting text to a camera function should update text-field.");
- XCTAssertEqualObjects(layer.text, functionStyleValue,
- @"text should round-trip camera functions.");
+ @"Setting text to a camera expression should update text-field.");
+ XCTAssertEqualObjects(layer.text, functionExpression,
+ @"text should round-trip camera expressions.");
layer.text = nil;
XCTAssertTrue(rawLayer->getTextField().isUndefined(),
@"Unsetting text should return text-field to the default value.");
- XCTAssertEqualObjects(layer.text, defaultStyleValue,
+ XCTAssertEqualObjects(layer.text, defaultExpression,
@"text should return the default value after being unset.");
}
@@ -940,72 +1046,81 @@
{
XCTAssertTrue(rawLayer->getTextAllowOverlap().isUndefined(),
@"text-allow-overlap should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textAllowsOverlap;
+ NSExpression *defaultExpression = layer.textAllowsOverlap;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
- layer.textAllowsOverlap = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"true"];
+ layer.textAllowsOverlap = constantExpression;
mbgl::style::PropertyValue<bool> propertyValue = { true };
XCTAssertEqual(rawLayer->getTextAllowOverlap(), propertyValue,
- @"Setting textAllowsOverlap to a constant value should update text-allow-overlap.");
- XCTAssertEqualObjects(layer.textAllowsOverlap, constantStyleValue,
- @"textAllowsOverlap should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textAllowsOverlap = functionStyleValue;
-
- mbgl::style::IntervalStops<bool> intervalStops = { {{18, true}} };
+ @"Setting textAllowsOverlap to a constant value expression should update text-allow-overlap.");
+ XCTAssertEqualObjects(layer.textAllowsOverlap, constantExpression,
+ @"textAllowsOverlap should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"true"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textAllowsOverlap = functionExpression;
+
+ mbgl::style::IntervalStops<bool> intervalStops = {{
+ { -INFINITY, true },
+ { 18, true },
+ }};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
XCTAssertEqual(rawLayer->getTextAllowOverlap(), propertyValue,
- @"Setting textAllowsOverlap to a camera function should update text-allow-overlap.");
- XCTAssertEqualObjects(layer.textAllowsOverlap, functionStyleValue,
- @"textAllowsOverlap should round-trip camera functions.");
+ @"Setting textAllowsOverlap to a camera expression should update text-allow-overlap.");
+ XCTAssertEqualObjects(layer.textAllowsOverlap, functionExpression,
+ @"textAllowsOverlap should round-trip camera expressions.");
layer.textAllowsOverlap = nil;
XCTAssertTrue(rawLayer->getTextAllowOverlap().isUndefined(),
@"Unsetting textAllowsOverlap should return text-allow-overlap to the default value.");
- XCTAssertEqualObjects(layer.textAllowsOverlap, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textAllowsOverlap, defaultExpression,
@"textAllowsOverlap should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textAllowsOverlap = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textAllowsOverlap = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.textAllowsOverlap = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.textAllowsOverlap = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// text-anchor
{
XCTAssertTrue(rawLayer->getTextAnchor().isUndefined(),
@"text-anchor should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.textAnchor;
+ NSExpression *defaultExpression = layer.textAnchor;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomRight]];
- layer.textAnchor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'bottom-right'"];
+ layer.textAnchor = constantExpression;
mbgl::style::DataDrivenPropertyValue<mbgl::style::SymbolAnchorType> propertyValue = { mbgl::style::SymbolAnchorType::BottomRight };
XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue,
- @"Setting textAnchor to a constant value should update text-anchor.");
- XCTAssertEqualObjects(layer.textAnchor, constantStyleValue,
- @"textAnchor should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textAnchor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::SymbolAnchorType> intervalStops = { {{18, mbgl::style::SymbolAnchorType::BottomRight}} };
+ @"Setting textAnchor to a constant value expression should update text-anchor.");
+ XCTAssertEqualObjects(layer.textAnchor, constantExpression,
+ @"textAnchor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'bottom-right'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textAnchor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::SymbolAnchorType> intervalStops = {{
+ { -INFINITY, mbgl::style::SymbolAnchorType::BottomRight },
+ { 18, mbgl::style::SymbolAnchorType::BottomRight },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::SymbolAnchorType> { intervalStops };
XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue,
- @"Setting textAnchor to a camera function should update text-anchor.");
- XCTAssertEqualObjects(layer.textAnchor, functionStyleValue,
- @"textAnchor should round-trip camera functions.");
+ @"Setting textAnchor to a camera expression should update text-anchor.");
+ XCTAssertEqualObjects(layer.textAnchor, functionExpression,
+ @"textAnchor should round-trip camera expressions.");
layer.textAnchor = nil;
XCTAssertTrue(rawLayer->getTextAnchor().isUndefined(),
@"Unsetting textAnchor should return text-anchor to the default value.");
- XCTAssertEqualObjects(layer.textAnchor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textAnchor, defaultExpression,
@"textAnchor should return the default value after being unset.");
}
@@ -1013,79 +1128,83 @@
{
XCTAssertTrue(rawLayer->getTextFont().isUndefined(),
@"text-font should be unset initially.");
- MGLStyleValue<NSArray<NSString *> *> *defaultStyleValue = layer.textFontNames;
+ NSExpression *defaultExpression = layer.textFontNames;
- MGLStyleValue<NSArray<NSString *> *> *constantStyleValue = [MGLStyleValue<NSArray<NSString *> *> valueWithRawValue:@[@"Text Font", @"Tnof Txet"]];
- layer.textFontNames = constantStyleValue;
- mbgl::style::PropertyValue<std::vector<std::string>> propertyValue = { { "Text Font", "Tnof Txet" } };
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"{'Text Font', 'Tnof Txet'}"];
+ layer.textFontNames = constantExpression;
+ mbgl::style::DataDrivenPropertyValue<std::vector<std::string>> propertyValue = { { "Text Font", "Tnof Txet" } };
XCTAssertEqual(rawLayer->getTextFont(), propertyValue,
- @"Setting textFontNames to a constant value should update text-font.");
- XCTAssertEqualObjects(layer.textFontNames, constantStyleValue,
- @"textFontNames should round-trip constant values.");
-
- MGLStyleValue<NSArray<NSString *> *> * functionStyleValue = [MGLStyleValue<NSArray<NSString *> *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textFontNames = functionStyleValue;
-
- mbgl::style::IntervalStops<std::vector<std::string>> intervalStops = { {{18, { "Text Font", "Tnof Txet" }}} };
+ @"Setting textFontNames to a constant value expression should update text-font.");
+ XCTAssertEqualObjects(layer.textFontNames, constantExpression,
+ @"textFontNames should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"{'Text Font', 'Tnof Txet'}"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textFontNames = functionExpression;
+
+ mbgl::style::IntervalStops<std::vector<std::string>> intervalStops = {{
+ { -INFINITY, { "Text Font", "Tnof Txet" } },
+ { 18, { "Text Font", "Tnof Txet" } },
+ }};
propertyValue = mbgl::style::CameraFunction<std::vector<std::string>> { intervalStops };
XCTAssertEqual(rawLayer->getTextFont(), propertyValue,
- @"Setting textFontNames to a camera function should update text-font.");
- XCTAssertEqualObjects(layer.textFontNames, functionStyleValue,
- @"textFontNames should round-trip camera functions.");
+ @"Setting textFontNames to a camera expression should update text-font.");
+ XCTAssertEqualObjects(layer.textFontNames, functionExpression,
+ @"textFontNames should round-trip camera expressions.");
layer.textFontNames = nil;
XCTAssertTrue(rawLayer->getTextFont().isUndefined(),
@"Unsetting textFontNames should return text-font to the default value.");
- XCTAssertEqualObjects(layer.textFontNames, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textFontNames, defaultExpression,
@"textFontNames should return the default value after being unset.");
-
- functionStyleValue = [MGLStyleValue<NSArray<NSString *> *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textFontNames = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSArray<NSString *> *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textFontNames = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// text-size
{
XCTAssertTrue(rawLayer->getTextSize().isUndefined(),
@"text-size should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textFontSize;
+ NSExpression *defaultExpression = layer.textFontSize;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.textFontSize = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.textFontSize = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextSize(), propertyValue,
- @"Setting textFontSize to a constant value should update text-size.");
- XCTAssertEqualObjects(layer.textFontSize, constantStyleValue,
- @"textFontSize should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textFontSize = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting textFontSize to a constant value expression should update text-size.");
+ XCTAssertEqualObjects(layer.textFontSize, constantExpression,
+ @"textFontSize should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textFontSize = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getTextSize(), propertyValue,
- @"Setting textFontSize to a camera function should update text-size.");
- XCTAssertEqualObjects(layer.textFontSize, functionStyleValue,
- @"textFontSize should round-trip camera functions.");
+ @"Setting textFontSize to a camera expression should update text-size.");
+ XCTAssertEqualObjects(layer.textFontSize, functionExpression,
+ @"textFontSize should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.textFontSize = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.textFontSize = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getTextSize(), propertyValue,
- @"Setting textFontSize to a source function should update text-size.");
- XCTAssertEqualObjects(layer.textFontSize, functionStyleValue,
- @"textFontSize should round-trip source functions.");
+ @"Setting textFontSize to a data expression should update text-size.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.textFontSize, pedanticFunctionExpression,
+ @"textFontSize should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.textFontSize = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.textFontSize = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -1093,15 +1212,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getTextSize(), propertyValue,
- @"Setting textFontSize to a composite function should update text-size.");
- XCTAssertEqualObjects(layer.textFontSize, functionStyleValue,
- @"textFontSize should round-trip composite functions.");
+ @"Setting textFontSize to a camera-data expression should update text-size.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.textFontSize, pedanticFunctionExpression,
+ @"textFontSize should round-trip camera-data expressions.");
layer.textFontSize = nil;
XCTAssertTrue(rawLayer->getTextSize().isUndefined(),
@"Unsetting textFontSize should return text-size to the default value.");
- XCTAssertEqualObjects(layer.textFontSize, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textFontSize, defaultExpression,
@"textFontSize should return the default value after being unset.");
}
@@ -1109,72 +1229,81 @@
{
XCTAssertTrue(rawLayer->getTextIgnorePlacement().isUndefined(),
@"text-ignore-placement should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textIgnoresPlacement;
+ NSExpression *defaultExpression = layer.textIgnoresPlacement;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
- layer.textIgnoresPlacement = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"true"];
+ layer.textIgnoresPlacement = constantExpression;
mbgl::style::PropertyValue<bool> propertyValue = { true };
XCTAssertEqual(rawLayer->getTextIgnorePlacement(), propertyValue,
- @"Setting textIgnoresPlacement to a constant value should update text-ignore-placement.");
- XCTAssertEqualObjects(layer.textIgnoresPlacement, constantStyleValue,
- @"textIgnoresPlacement should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textIgnoresPlacement = functionStyleValue;
-
- mbgl::style::IntervalStops<bool> intervalStops = { {{18, true}} };
+ @"Setting textIgnoresPlacement to a constant value expression should update text-ignore-placement.");
+ XCTAssertEqualObjects(layer.textIgnoresPlacement, constantExpression,
+ @"textIgnoresPlacement should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"true"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textIgnoresPlacement = functionExpression;
+
+ mbgl::style::IntervalStops<bool> intervalStops = {{
+ { -INFINITY, true },
+ { 18, true },
+ }};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
XCTAssertEqual(rawLayer->getTextIgnorePlacement(), propertyValue,
- @"Setting textIgnoresPlacement to a camera function should update text-ignore-placement.");
- XCTAssertEqualObjects(layer.textIgnoresPlacement, functionStyleValue,
- @"textIgnoresPlacement should round-trip camera functions.");
+ @"Setting textIgnoresPlacement to a camera expression should update text-ignore-placement.");
+ XCTAssertEqualObjects(layer.textIgnoresPlacement, functionExpression,
+ @"textIgnoresPlacement should round-trip camera expressions.");
layer.textIgnoresPlacement = nil;
XCTAssertTrue(rawLayer->getTextIgnorePlacement().isUndefined(),
@"Unsetting textIgnoresPlacement should return text-ignore-placement to the default value.");
- XCTAssertEqualObjects(layer.textIgnoresPlacement, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textIgnoresPlacement, defaultExpression,
@"textIgnoresPlacement should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textIgnoresPlacement = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textIgnoresPlacement = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.textIgnoresPlacement = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.textIgnoresPlacement = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// text-justify
{
XCTAssertTrue(rawLayer->getTextJustify().isUndefined(),
@"text-justify should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.textJustification;
+ NSExpression *defaultExpression = layer.textJustification;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextJustification:MGLTextJustificationRight]];
- layer.textJustification = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'right'"];
+ layer.textJustification = constantExpression;
mbgl::style::DataDrivenPropertyValue<mbgl::style::TextJustifyType> propertyValue = { mbgl::style::TextJustifyType::Right };
XCTAssertEqual(rawLayer->getTextJustify(), propertyValue,
- @"Setting textJustification to a constant value should update text-justify.");
- XCTAssertEqualObjects(layer.textJustification, constantStyleValue,
- @"textJustification should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textJustification = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::TextJustifyType> intervalStops = { {{18, mbgl::style::TextJustifyType::Right}} };
+ @"Setting textJustification to a constant value expression should update text-justify.");
+ XCTAssertEqualObjects(layer.textJustification, constantExpression,
+ @"textJustification should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'right'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textJustification = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::TextJustifyType> intervalStops = {{
+ { -INFINITY, mbgl::style::TextJustifyType::Right },
+ { 18, mbgl::style::TextJustifyType::Right },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TextJustifyType> { intervalStops };
XCTAssertEqual(rawLayer->getTextJustify(), propertyValue,
- @"Setting textJustification to a camera function should update text-justify.");
- XCTAssertEqualObjects(layer.textJustification, functionStyleValue,
- @"textJustification should round-trip camera functions.");
+ @"Setting textJustification to a camera expression should update text-justify.");
+ XCTAssertEqualObjects(layer.textJustification, functionExpression,
+ @"textJustification should round-trip camera expressions.");
layer.textJustification = nil;
XCTAssertTrue(rawLayer->getTextJustify().isUndefined(),
@"Unsetting textJustification should return text-justify to the default value.");
- XCTAssertEqualObjects(layer.textJustification, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textJustification, defaultExpression,
@"textJustification should return the default value after being unset.");
}
@@ -1182,40 +1311,45 @@
{
XCTAssertTrue(rawLayer->getTextLetterSpacing().isUndefined(),
@"text-letter-spacing should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textLetterSpacing;
+ NSExpression *defaultExpression = layer.textLetterSpacing;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.textLetterSpacing = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.textLetterSpacing = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue,
- @"Setting textLetterSpacing to a constant value should update text-letter-spacing.");
- XCTAssertEqualObjects(layer.textLetterSpacing, constantStyleValue,
- @"textLetterSpacing should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textLetterSpacing = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting textLetterSpacing to a constant value expression should update text-letter-spacing.");
+ XCTAssertEqualObjects(layer.textLetterSpacing, constantExpression,
+ @"textLetterSpacing should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textLetterSpacing = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue,
- @"Setting textLetterSpacing to a camera function should update text-letter-spacing.");
- XCTAssertEqualObjects(layer.textLetterSpacing, functionStyleValue,
- @"textLetterSpacing should round-trip camera functions.");
+ @"Setting textLetterSpacing to a camera expression should update text-letter-spacing.");
+ XCTAssertEqualObjects(layer.textLetterSpacing, functionExpression,
+ @"textLetterSpacing should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.textLetterSpacing = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.textLetterSpacing = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue,
- @"Setting textLetterSpacing to a source function should update text-letter-spacing.");
- XCTAssertEqualObjects(layer.textLetterSpacing, functionStyleValue,
- @"textLetterSpacing should round-trip source functions.");
+ @"Setting textLetterSpacing to a data expression should update text-letter-spacing.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.textLetterSpacing, pedanticFunctionExpression,
+ @"textLetterSpacing should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.textLetterSpacing = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.textLetterSpacing = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -1223,15 +1357,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue,
- @"Setting textLetterSpacing to a composite function should update text-letter-spacing.");
- XCTAssertEqualObjects(layer.textLetterSpacing, functionStyleValue,
- @"textLetterSpacing should round-trip composite functions.");
+ @"Setting textLetterSpacing to a camera-data expression should update text-letter-spacing.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.textLetterSpacing, pedanticFunctionExpression,
+ @"textLetterSpacing should round-trip camera-data expressions.");
layer.textLetterSpacing = nil;
XCTAssertTrue(rawLayer->getTextLetterSpacing().isUndefined(),
@"Unsetting textLetterSpacing should return text-letter-spacing to the default value.");
- XCTAssertEqualObjects(layer.textLetterSpacing, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textLetterSpacing, defaultExpression,
@"textLetterSpacing should return the default value after being unset.");
}
@@ -1239,85 +1374,95 @@
{
XCTAssertTrue(rawLayer->getTextLineHeight().isUndefined(),
@"text-line-height should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textLineHeight;
+ NSExpression *defaultExpression = layer.textLineHeight;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.textLineHeight = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.textLineHeight = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextLineHeight(), propertyValue,
- @"Setting textLineHeight to a constant value should update text-line-height.");
- XCTAssertEqualObjects(layer.textLineHeight, constantStyleValue,
- @"textLineHeight should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textLineHeight = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting textLineHeight to a constant value expression should update text-line-height.");
+ XCTAssertEqualObjects(layer.textLineHeight, constantExpression,
+ @"textLineHeight should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textLineHeight = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getTextLineHeight(), propertyValue,
- @"Setting textLineHeight to a camera function should update text-line-height.");
- XCTAssertEqualObjects(layer.textLineHeight, functionStyleValue,
- @"textLineHeight should round-trip camera functions.");
+ @"Setting textLineHeight to a camera expression should update text-line-height.");
+ XCTAssertEqualObjects(layer.textLineHeight, functionExpression,
+ @"textLineHeight should round-trip camera expressions.");
layer.textLineHeight = nil;
XCTAssertTrue(rawLayer->getTextLineHeight().isUndefined(),
@"Unsetting textLineHeight should return text-line-height to the default value.");
- XCTAssertEqualObjects(layer.textLineHeight, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textLineHeight, defaultExpression,
@"textLineHeight should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textLineHeight = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textLineHeight = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.textLineHeight = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.textLineHeight = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// text-offset
{
XCTAssertTrue(rawLayer->getTextOffset().isUndefined(),
@"text-offset should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.textOffset;
+ NSExpression *defaultExpression = layer.textOffset;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@",
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
- layer.textOffset = constantStyleValue;
+ layer.textOffset = constantExpression;
mbgl::style::DataDrivenPropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getTextOffset(), propertyValue,
- @"Setting textOffset to a constant value should update text-offset.");
- XCTAssertEqualObjects(layer.textOffset, constantStyleValue,
- @"textOffset should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textOffset = functionStyleValue;
-
- mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} };
+ @"Setting textOffset to a constant value expression should update text-offset.");
+ XCTAssertEqualObjects(layer.textOffset, constantExpression,
+ @"textOffset should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"{1, 1}"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textOffset = functionExpression;
+
+ mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = {{
+ { -INFINITY, { 1, 1 } },
+ { 18, { 1, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
XCTAssertEqual(rawLayer->getTextOffset(), propertyValue,
- @"Setting textOffset to a camera function should update text-offset.");
- XCTAssertEqualObjects(layer.textOffset, functionStyleValue,
- @"textOffset should round-trip camera functions.");
+ @"Setting textOffset to a camera expression should update text-offset.");
+ XCTAssertEqualObjects(layer.textOffset, functionExpression,
+ @"textOffset should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.textOffset = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.textOffset = functionExpression;
mbgl::style::ExponentialStops<std::array<float, 2>> exponentialStops = { {{18, { 1, 1 }}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<std::array<float, 2>> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getTextOffset(), propertyValue,
- @"Setting textOffset to a source function should update text-offset.");
- XCTAssertEqualObjects(layer.textOffset, functionStyleValue,
- @"textOffset should round-trip source functions.");
+ @"Setting textOffset to a data expression should update text-offset.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.textOffset, pedanticFunctionExpression,
+ @"textOffset should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.textOffset = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.textOffset = functionExpression;
std::map<float, std::array<float, 2>> innerStops { {18, { 1, 1 }} };
mbgl::style::CompositeExponentialStops<std::array<float, 2>> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -1325,15 +1470,16 @@
propertyValue = mbgl::style::CompositeFunction<std::array<float, 2>> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getTextOffset(), propertyValue,
- @"Setting textOffset to a composite function should update text-offset.");
- XCTAssertEqualObjects(layer.textOffset, functionStyleValue,
- @"textOffset should round-trip composite functions.");
+ @"Setting textOffset to a camera-data expression should update text-offset.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.textOffset, pedanticFunctionExpression,
+ @"textOffset should round-trip camera-data expressions.");
layer.textOffset = nil;
XCTAssertTrue(rawLayer->getTextOffset().isUndefined(),
@"Unsetting textOffset should return text-offset to the default value.");
- XCTAssertEqualObjects(layer.textOffset, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textOffset, defaultExpression,
@"textOffset should return the default value after being unset.");
}
@@ -1341,157 +1487,177 @@
{
XCTAssertTrue(rawLayer->getTextOptional().isUndefined(),
@"text-optional should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textOptional;
+ NSExpression *defaultExpression = layer.textOptional;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
- layer.textOptional = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"true"];
+ layer.textOptional = constantExpression;
mbgl::style::PropertyValue<bool> propertyValue = { true };
XCTAssertEqual(rawLayer->getTextOptional(), propertyValue,
- @"Setting textOptional to a constant value should update text-optional.");
- XCTAssertEqualObjects(layer.textOptional, constantStyleValue,
- @"textOptional should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textOptional = functionStyleValue;
-
- mbgl::style::IntervalStops<bool> intervalStops = { {{18, true}} };
+ @"Setting textOptional to a constant value expression should update text-optional.");
+ XCTAssertEqualObjects(layer.textOptional, constantExpression,
+ @"textOptional should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"true"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textOptional = functionExpression;
+
+ mbgl::style::IntervalStops<bool> intervalStops = {{
+ { -INFINITY, true },
+ { 18, true },
+ }};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
XCTAssertEqual(rawLayer->getTextOptional(), propertyValue,
- @"Setting textOptional to a camera function should update text-optional.");
- XCTAssertEqualObjects(layer.textOptional, functionStyleValue,
- @"textOptional should round-trip camera functions.");
+ @"Setting textOptional to a camera expression should update text-optional.");
+ XCTAssertEqualObjects(layer.textOptional, functionExpression,
+ @"textOptional should round-trip camera expressions.");
layer.textOptional = nil;
XCTAssertTrue(rawLayer->getTextOptional().isUndefined(),
@"Unsetting textOptional should return text-optional to the default value.");
- XCTAssertEqualObjects(layer.textOptional, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textOptional, defaultExpression,
@"textOptional should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textOptional = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textOptional = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.textOptional = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.textOptional = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// text-padding
{
XCTAssertTrue(rawLayer->getTextPadding().isUndefined(),
@"text-padding should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textPadding;
+ NSExpression *defaultExpression = layer.textPadding;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.textPadding = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.textPadding = constantExpression;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextPadding(), propertyValue,
- @"Setting textPadding to a constant value should update text-padding.");
- XCTAssertEqualObjects(layer.textPadding, constantStyleValue,
- @"textPadding should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textPadding = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting textPadding to a constant value expression should update text-padding.");
+ XCTAssertEqualObjects(layer.textPadding, constantExpression,
+ @"textPadding should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textPadding = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getTextPadding(), propertyValue,
- @"Setting textPadding to a camera function should update text-padding.");
- XCTAssertEqualObjects(layer.textPadding, functionStyleValue,
- @"textPadding should round-trip camera functions.");
+ @"Setting textPadding to a camera expression should update text-padding.");
+ XCTAssertEqualObjects(layer.textPadding, functionExpression,
+ @"textPadding should round-trip camera expressions.");
layer.textPadding = nil;
XCTAssertTrue(rawLayer->getTextPadding().isUndefined(),
@"Unsetting textPadding should return text-padding to the default value.");
- XCTAssertEqualObjects(layer.textPadding, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textPadding, defaultExpression,
@"textPadding should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textPadding = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textPadding = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.textPadding = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.textPadding = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// text-pitch-alignment
{
XCTAssertTrue(rawLayer->getTextPitchAlignment().isUndefined(),
@"text-pitch-alignment should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.textPitchAlignment;
+ NSExpression *defaultExpression = layer.textPitchAlignment;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextPitchAlignment:MGLTextPitchAlignmentAuto]];
- layer.textPitchAlignment = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'auto'"];
+ layer.textPitchAlignment = constantExpression;
mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Auto };
XCTAssertEqual(rawLayer->getTextPitchAlignment(), propertyValue,
- @"Setting textPitchAlignment to a constant value should update text-pitch-alignment.");
- XCTAssertEqualObjects(layer.textPitchAlignment, constantStyleValue,
- @"textPitchAlignment should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textPitchAlignment = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = { {{18, mbgl::style::AlignmentType::Auto}} };
+ @"Setting textPitchAlignment to a constant value expression should update text-pitch-alignment.");
+ XCTAssertEqualObjects(layer.textPitchAlignment, constantExpression,
+ @"textPitchAlignment should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'auto'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textPitchAlignment = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = {{
+ { -INFINITY, mbgl::style::AlignmentType::Auto },
+ { 18, mbgl::style::AlignmentType::Auto },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
XCTAssertEqual(rawLayer->getTextPitchAlignment(), propertyValue,
- @"Setting textPitchAlignment to a camera function should update text-pitch-alignment.");
- XCTAssertEqualObjects(layer.textPitchAlignment, functionStyleValue,
- @"textPitchAlignment should round-trip camera functions.");
+ @"Setting textPitchAlignment to a camera expression should update text-pitch-alignment.");
+ XCTAssertEqualObjects(layer.textPitchAlignment, functionExpression,
+ @"textPitchAlignment should round-trip camera expressions.");
layer.textPitchAlignment = nil;
XCTAssertTrue(rawLayer->getTextPitchAlignment().isUndefined(),
@"Unsetting textPitchAlignment should return text-pitch-alignment to the default value.");
- XCTAssertEqualObjects(layer.textPitchAlignment, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textPitchAlignment, defaultExpression,
@"textPitchAlignment should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textPitchAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textPitchAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.textPitchAlignment = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.textPitchAlignment = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// text-rotate
{
XCTAssertTrue(rawLayer->getTextRotate().isUndefined(),
@"text-rotate should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textRotation;
+ NSExpression *defaultExpression = layer.textRotation;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.textRotation = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.textRotation = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextRotate(), propertyValue,
- @"Setting textRotation to a constant value should update text-rotate.");
- XCTAssertEqualObjects(layer.textRotation, constantStyleValue,
- @"textRotation should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textRotation = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting textRotation to a constant value expression should update text-rotate.");
+ XCTAssertEqualObjects(layer.textRotation, constantExpression,
+ @"textRotation should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textRotation = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getTextRotate(), propertyValue,
- @"Setting textRotation to a camera function should update text-rotate.");
- XCTAssertEqualObjects(layer.textRotation, functionStyleValue,
- @"textRotation should round-trip camera functions.");
+ @"Setting textRotation to a camera expression should update text-rotate.");
+ XCTAssertEqualObjects(layer.textRotation, functionExpression,
+ @"textRotation should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.textRotation = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.textRotation = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getTextRotate(), propertyValue,
- @"Setting textRotation to a source function should update text-rotate.");
- XCTAssertEqualObjects(layer.textRotation, functionStyleValue,
- @"textRotation should round-trip source functions.");
+ @"Setting textRotation to a data expression should update text-rotate.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.textRotation, pedanticFunctionExpression,
+ @"textRotation should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.textRotation = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.textRotation = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -1499,15 +1665,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getTextRotate(), propertyValue,
- @"Setting textRotation to a composite function should update text-rotate.");
- XCTAssertEqualObjects(layer.textRotation, functionStyleValue,
- @"textRotation should round-trip composite functions.");
+ @"Setting textRotation to a camera-data expression should update text-rotate.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.textRotation, pedanticFunctionExpression,
+ @"textRotation should round-trip camera-data expressions.");
layer.textRotation = nil;
XCTAssertTrue(rawLayer->getTextRotate().isUndefined(),
@"Unsetting textRotation should return text-rotate to the default value.");
- XCTAssertEqualObjects(layer.textRotation, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textRotation, defaultExpression,
@"textRotation should return the default value after being unset.");
}
@@ -1515,72 +1682,81 @@
{
XCTAssertTrue(rawLayer->getTextRotationAlignment().isUndefined(),
@"text-rotation-alignment should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.textRotationAlignment;
+ NSExpression *defaultExpression = layer.textRotationAlignment;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextRotationAlignment:MGLTextRotationAlignmentAuto]];
- layer.textRotationAlignment = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'auto'"];
+ layer.textRotationAlignment = constantExpression;
mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Auto };
XCTAssertEqual(rawLayer->getTextRotationAlignment(), propertyValue,
- @"Setting textRotationAlignment to a constant value should update text-rotation-alignment.");
- XCTAssertEqualObjects(layer.textRotationAlignment, constantStyleValue,
- @"textRotationAlignment should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textRotationAlignment = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = { {{18, mbgl::style::AlignmentType::Auto}} };
+ @"Setting textRotationAlignment to a constant value expression should update text-rotation-alignment.");
+ XCTAssertEqualObjects(layer.textRotationAlignment, constantExpression,
+ @"textRotationAlignment should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'auto'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textRotationAlignment = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = {{
+ { -INFINITY, mbgl::style::AlignmentType::Auto },
+ { 18, mbgl::style::AlignmentType::Auto },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
XCTAssertEqual(rawLayer->getTextRotationAlignment(), propertyValue,
- @"Setting textRotationAlignment to a camera function should update text-rotation-alignment.");
- XCTAssertEqualObjects(layer.textRotationAlignment, functionStyleValue,
- @"textRotationAlignment should round-trip camera functions.");
+ @"Setting textRotationAlignment to a camera expression should update text-rotation-alignment.");
+ XCTAssertEqualObjects(layer.textRotationAlignment, functionExpression,
+ @"textRotationAlignment should round-trip camera expressions.");
layer.textRotationAlignment = nil;
XCTAssertTrue(rawLayer->getTextRotationAlignment().isUndefined(),
@"Unsetting textRotationAlignment should return text-rotation-alignment to the default value.");
- XCTAssertEqualObjects(layer.textRotationAlignment, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textRotationAlignment, defaultExpression,
@"textRotationAlignment should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textRotationAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textRotationAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.textRotationAlignment = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.textRotationAlignment = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// text-transform
{
XCTAssertTrue(rawLayer->getTextTransform().isUndefined(),
@"text-transform should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.textTransform;
+ NSExpression *defaultExpression = layer.textTransform;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextTransform:MGLTextTransformLowercase]];
- layer.textTransform = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'lowercase'"];
+ layer.textTransform = constantExpression;
mbgl::style::DataDrivenPropertyValue<mbgl::style::TextTransformType> propertyValue = { mbgl::style::TextTransformType::Lowercase };
XCTAssertEqual(rawLayer->getTextTransform(), propertyValue,
- @"Setting textTransform to a constant value should update text-transform.");
- XCTAssertEqualObjects(layer.textTransform, constantStyleValue,
- @"textTransform should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textTransform = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::TextTransformType> intervalStops = { {{18, mbgl::style::TextTransformType::Lowercase}} };
+ @"Setting textTransform to a constant value expression should update text-transform.");
+ XCTAssertEqualObjects(layer.textTransform, constantExpression,
+ @"textTransform should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'lowercase'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textTransform = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::TextTransformType> intervalStops = {{
+ { -INFINITY, mbgl::style::TextTransformType::Lowercase },
+ { 18, mbgl::style::TextTransformType::Lowercase },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TextTransformType> { intervalStops };
XCTAssertEqual(rawLayer->getTextTransform(), propertyValue,
- @"Setting textTransform to a camera function should update text-transform.");
- XCTAssertEqualObjects(layer.textTransform, functionStyleValue,
- @"textTransform should round-trip camera functions.");
+ @"Setting textTransform to a camera expression should update text-transform.");
+ XCTAssertEqualObjects(layer.textTransform, functionExpression,
+ @"textTransform should round-trip camera expressions.");
layer.textTransform = nil;
XCTAssertTrue(rawLayer->getTextTransform().isUndefined(),
@"Unsetting textTransform should return text-transform to the default value.");
- XCTAssertEqualObjects(layer.textTransform, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textTransform, defaultExpression,
@"textTransform should return the default value after being unset.");
}
@@ -1588,40 +1764,45 @@
{
XCTAssertTrue(rawLayer->getIconColor().isUndefined(),
@"icon-color should be unset initially.");
- MGLStyleValue<MGLColor *> *defaultStyleValue = layer.iconColor;
+ NSExpression *defaultExpression = layer.iconColor;
- MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.iconColor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ layer.iconColor = constantExpression;
mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getIconColor(), propertyValue,
- @"Setting iconColor to a constant value should update icon-color.");
- XCTAssertEqualObjects(layer.iconColor, constantStyleValue,
- @"iconColor should round-trip constant values.");
-
- MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconColor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ @"Setting iconColor to a constant value expression should update icon-color.");
+ XCTAssertEqualObjects(layer.iconColor, constantExpression,
+ @"iconColor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconColor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = {{
+ { -INFINITY, { 1, 0, 0, 1 } },
+ { 18, { 1, 0, 0, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
XCTAssertEqual(rawLayer->getIconColor(), propertyValue,
- @"Setting iconColor to a camera function should update icon-color.");
- XCTAssertEqualObjects(layer.iconColor, functionStyleValue,
- @"iconColor should round-trip camera functions.");
+ @"Setting iconColor to a camera expression should update icon-color.");
+ XCTAssertEqualObjects(layer.iconColor, functionExpression,
+ @"iconColor should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.iconColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.iconColor = functionExpression;
mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getIconColor(), propertyValue,
- @"Setting iconColor to a source function should update icon-color.");
- XCTAssertEqualObjects(layer.iconColor, functionStyleValue,
- @"iconColor should round-trip source functions.");
+ @"Setting iconColor to a data expression should update icon-color.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.iconColor, pedanticFunctionExpression,
+ @"iconColor should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.iconColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.iconColor = functionExpression;
std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -1629,15 +1810,16 @@
propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getIconColor(), propertyValue,
- @"Setting iconColor to a composite function should update icon-color.");
- XCTAssertEqualObjects(layer.iconColor, functionStyleValue,
- @"iconColor should round-trip composite functions.");
+ @"Setting iconColor to a camera-data expression should update icon-color.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.iconColor, pedanticFunctionExpression,
+ @"iconColor should round-trip camera-data expressions.");
layer.iconColor = nil;
XCTAssertTrue(rawLayer->getIconColor().isUndefined(),
@"Unsetting iconColor should return icon-color to the default value.");
- XCTAssertEqualObjects(layer.iconColor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconColor, defaultExpression,
@"iconColor should return the default value after being unset.");
// Transition property test
layer.iconColorTransition = transitionTest;
@@ -1654,40 +1836,45 @@
{
XCTAssertTrue(rawLayer->getIconHaloBlur().isUndefined(),
@"icon-halo-blur should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconHaloBlur;
+ NSExpression *defaultExpression = layer.iconHaloBlur;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.iconHaloBlur = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.iconHaloBlur = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue,
- @"Setting iconHaloBlur to a constant value should update icon-halo-blur.");
- XCTAssertEqualObjects(layer.iconHaloBlur, constantStyleValue,
- @"iconHaloBlur should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconHaloBlur = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting iconHaloBlur to a constant value expression should update icon-halo-blur.");
+ XCTAssertEqualObjects(layer.iconHaloBlur, constantExpression,
+ @"iconHaloBlur should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconHaloBlur = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue,
- @"Setting iconHaloBlur to a camera function should update icon-halo-blur.");
- XCTAssertEqualObjects(layer.iconHaloBlur, functionStyleValue,
- @"iconHaloBlur should round-trip camera functions.");
+ @"Setting iconHaloBlur to a camera expression should update icon-halo-blur.");
+ XCTAssertEqualObjects(layer.iconHaloBlur, functionExpression,
+ @"iconHaloBlur should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.iconHaloBlur = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.iconHaloBlur = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue,
- @"Setting iconHaloBlur to a source function should update icon-halo-blur.");
- XCTAssertEqualObjects(layer.iconHaloBlur, functionStyleValue,
- @"iconHaloBlur should round-trip source functions.");
+ @"Setting iconHaloBlur to a data expression should update icon-halo-blur.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.iconHaloBlur, pedanticFunctionExpression,
+ @"iconHaloBlur should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.iconHaloBlur = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.iconHaloBlur = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -1695,15 +1882,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue,
- @"Setting iconHaloBlur to a composite function should update icon-halo-blur.");
- XCTAssertEqualObjects(layer.iconHaloBlur, functionStyleValue,
- @"iconHaloBlur should round-trip composite functions.");
+ @"Setting iconHaloBlur to a camera-data expression should update icon-halo-blur.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.iconHaloBlur, pedanticFunctionExpression,
+ @"iconHaloBlur should round-trip camera-data expressions.");
layer.iconHaloBlur = nil;
XCTAssertTrue(rawLayer->getIconHaloBlur().isUndefined(),
@"Unsetting iconHaloBlur should return icon-halo-blur to the default value.");
- XCTAssertEqualObjects(layer.iconHaloBlur, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconHaloBlur, defaultExpression,
@"iconHaloBlur should return the default value after being unset.");
// Transition property test
layer.iconHaloBlurTransition = transitionTest;
@@ -1720,40 +1908,45 @@
{
XCTAssertTrue(rawLayer->getIconHaloColor().isUndefined(),
@"icon-halo-color should be unset initially.");
- MGLStyleValue<MGLColor *> *defaultStyleValue = layer.iconHaloColor;
+ NSExpression *defaultExpression = layer.iconHaloColor;
- MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.iconHaloColor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ layer.iconHaloColor = constantExpression;
mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue,
- @"Setting iconHaloColor to a constant value should update icon-halo-color.");
- XCTAssertEqualObjects(layer.iconHaloColor, constantStyleValue,
- @"iconHaloColor should round-trip constant values.");
-
- MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconHaloColor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ @"Setting iconHaloColor to a constant value expression should update icon-halo-color.");
+ XCTAssertEqualObjects(layer.iconHaloColor, constantExpression,
+ @"iconHaloColor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconHaloColor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = {{
+ { -INFINITY, { 1, 0, 0, 1 } },
+ { 18, { 1, 0, 0, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue,
- @"Setting iconHaloColor to a camera function should update icon-halo-color.");
- XCTAssertEqualObjects(layer.iconHaloColor, functionStyleValue,
- @"iconHaloColor should round-trip camera functions.");
+ @"Setting iconHaloColor to a camera expression should update icon-halo-color.");
+ XCTAssertEqualObjects(layer.iconHaloColor, functionExpression,
+ @"iconHaloColor should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.iconHaloColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.iconHaloColor = functionExpression;
mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue,
- @"Setting iconHaloColor to a source function should update icon-halo-color.");
- XCTAssertEqualObjects(layer.iconHaloColor, functionStyleValue,
- @"iconHaloColor should round-trip source functions.");
+ @"Setting iconHaloColor to a data expression should update icon-halo-color.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.iconHaloColor, pedanticFunctionExpression,
+ @"iconHaloColor should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.iconHaloColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.iconHaloColor = functionExpression;
std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -1761,15 +1954,16 @@
propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue,
- @"Setting iconHaloColor to a composite function should update icon-halo-color.");
- XCTAssertEqualObjects(layer.iconHaloColor, functionStyleValue,
- @"iconHaloColor should round-trip composite functions.");
+ @"Setting iconHaloColor to a camera-data expression should update icon-halo-color.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.iconHaloColor, pedanticFunctionExpression,
+ @"iconHaloColor should round-trip camera-data expressions.");
layer.iconHaloColor = nil;
XCTAssertTrue(rawLayer->getIconHaloColor().isUndefined(),
@"Unsetting iconHaloColor should return icon-halo-color to the default value.");
- XCTAssertEqualObjects(layer.iconHaloColor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconHaloColor, defaultExpression,
@"iconHaloColor should return the default value after being unset.");
// Transition property test
layer.iconHaloColorTransition = transitionTest;
@@ -1786,40 +1980,45 @@
{
XCTAssertTrue(rawLayer->getIconHaloWidth().isUndefined(),
@"icon-halo-width should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconHaloWidth;
+ NSExpression *defaultExpression = layer.iconHaloWidth;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.iconHaloWidth = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.iconHaloWidth = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue,
- @"Setting iconHaloWidth to a constant value should update icon-halo-width.");
- XCTAssertEqualObjects(layer.iconHaloWidth, constantStyleValue,
- @"iconHaloWidth should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconHaloWidth = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting iconHaloWidth to a constant value expression should update icon-halo-width.");
+ XCTAssertEqualObjects(layer.iconHaloWidth, constantExpression,
+ @"iconHaloWidth should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconHaloWidth = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue,
- @"Setting iconHaloWidth to a camera function should update icon-halo-width.");
- XCTAssertEqualObjects(layer.iconHaloWidth, functionStyleValue,
- @"iconHaloWidth should round-trip camera functions.");
+ @"Setting iconHaloWidth to a camera expression should update icon-halo-width.");
+ XCTAssertEqualObjects(layer.iconHaloWidth, functionExpression,
+ @"iconHaloWidth should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.iconHaloWidth = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.iconHaloWidth = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue,
- @"Setting iconHaloWidth to a source function should update icon-halo-width.");
- XCTAssertEqualObjects(layer.iconHaloWidth, functionStyleValue,
- @"iconHaloWidth should round-trip source functions.");
+ @"Setting iconHaloWidth to a data expression should update icon-halo-width.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.iconHaloWidth, pedanticFunctionExpression,
+ @"iconHaloWidth should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.iconHaloWidth = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.iconHaloWidth = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -1827,15 +2026,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue,
- @"Setting iconHaloWidth to a composite function should update icon-halo-width.");
- XCTAssertEqualObjects(layer.iconHaloWidth, functionStyleValue,
- @"iconHaloWidth should round-trip composite functions.");
+ @"Setting iconHaloWidth to a camera-data expression should update icon-halo-width.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.iconHaloWidth, pedanticFunctionExpression,
+ @"iconHaloWidth should round-trip camera-data expressions.");
layer.iconHaloWidth = nil;
XCTAssertTrue(rawLayer->getIconHaloWidth().isUndefined(),
@"Unsetting iconHaloWidth should return icon-halo-width to the default value.");
- XCTAssertEqualObjects(layer.iconHaloWidth, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconHaloWidth, defaultExpression,
@"iconHaloWidth should return the default value after being unset.");
// Transition property test
layer.iconHaloWidthTransition = transitionTest;
@@ -1852,40 +2052,45 @@
{
XCTAssertTrue(rawLayer->getIconOpacity().isUndefined(),
@"icon-opacity should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconOpacity;
+ NSExpression *defaultExpression = layer.iconOpacity;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.iconOpacity = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.iconOpacity = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue,
- @"Setting iconOpacity to a constant value should update icon-opacity.");
- XCTAssertEqualObjects(layer.iconOpacity, constantStyleValue,
- @"iconOpacity should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconOpacity = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting iconOpacity to a constant value expression should update icon-opacity.");
+ XCTAssertEqualObjects(layer.iconOpacity, constantExpression,
+ @"iconOpacity should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconOpacity = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue,
- @"Setting iconOpacity to a camera function should update icon-opacity.");
- XCTAssertEqualObjects(layer.iconOpacity, functionStyleValue,
- @"iconOpacity should round-trip camera functions.");
+ @"Setting iconOpacity to a camera expression should update icon-opacity.");
+ XCTAssertEqualObjects(layer.iconOpacity, functionExpression,
+ @"iconOpacity should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.iconOpacity = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.iconOpacity = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue,
- @"Setting iconOpacity to a source function should update icon-opacity.");
- XCTAssertEqualObjects(layer.iconOpacity, functionStyleValue,
- @"iconOpacity should round-trip source functions.");
+ @"Setting iconOpacity to a data expression should update icon-opacity.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.iconOpacity, pedanticFunctionExpression,
+ @"iconOpacity should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.iconOpacity = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.iconOpacity = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -1893,15 +2098,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue,
- @"Setting iconOpacity to a composite function should update icon-opacity.");
- XCTAssertEqualObjects(layer.iconOpacity, functionStyleValue,
- @"iconOpacity should round-trip composite functions.");
+ @"Setting iconOpacity to a camera-data expression should update icon-opacity.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.iconOpacity, pedanticFunctionExpression,
+ @"iconOpacity should round-trip camera-data expressions.");
layer.iconOpacity = nil;
XCTAssertTrue(rawLayer->getIconOpacity().isUndefined(),
@"Unsetting iconOpacity should return icon-opacity to the default value.");
- XCTAssertEqualObjects(layer.iconOpacity, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconOpacity, defaultExpression,
@"iconOpacity should return the default value after being unset.");
// Transition property test
layer.iconOpacityTransition = transitionTest;
@@ -1918,124 +2124,139 @@
{
XCTAssertTrue(rawLayer->getIconTranslate().isUndefined(),
@"icon-translate should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconTranslation;
+ NSExpression *defaultExpression = layer.iconTranslation;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@",
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
- layer.iconTranslation = constantStyleValue;
+ layer.iconTranslation = constantExpression;
mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getIconTranslate(), propertyValue,
- @"Setting iconTranslation to a constant value should update icon-translate.");
- XCTAssertEqualObjects(layer.iconTranslation, constantStyleValue,
- @"iconTranslation should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconTranslation = functionStyleValue;
-
- mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} };
+ @"Setting iconTranslation to a constant value expression should update icon-translate.");
+ XCTAssertEqualObjects(layer.iconTranslation, constantExpression,
+ @"iconTranslation should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"{1, 1}"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconTranslation = functionExpression;
+
+ mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = {{
+ { -INFINITY, { 1, 1 } },
+ { 18, { 1, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
XCTAssertEqual(rawLayer->getIconTranslate(), propertyValue,
- @"Setting iconTranslation to a camera function should update icon-translate.");
- XCTAssertEqualObjects(layer.iconTranslation, functionStyleValue,
- @"iconTranslation should round-trip camera functions.");
+ @"Setting iconTranslation to a camera expression should update icon-translate.");
+ XCTAssertEqualObjects(layer.iconTranslation, functionExpression,
+ @"iconTranslation should round-trip camera expressions.");
layer.iconTranslation = nil;
XCTAssertTrue(rawLayer->getIconTranslate().isUndefined(),
@"Unsetting iconTranslation should return icon-translate to the default value.");
- XCTAssertEqualObjects(layer.iconTranslation, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconTranslation, defaultExpression,
@"iconTranslation should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.iconTranslation = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.iconTranslation = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// icon-translate-anchor
{
XCTAssertTrue(rawLayer->getIconTranslateAnchor().isUndefined(),
@"icon-translate-anchor should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconTranslationAnchor;
+ NSExpression *defaultExpression = layer.iconTranslationAnchor;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconTranslationAnchor:MGLIconTranslationAnchorViewport]];
- layer.iconTranslationAnchor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ layer.iconTranslationAnchor = constantExpression;
mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
XCTAssertEqual(rawLayer->getIconTranslateAnchor(), propertyValue,
- @"Setting iconTranslationAnchor to a constant value should update icon-translate-anchor.");
- XCTAssertEqualObjects(layer.iconTranslationAnchor, constantStyleValue,
- @"iconTranslationAnchor should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.iconTranslationAnchor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} };
+ @"Setting iconTranslationAnchor to a constant value expression should update icon-translate-anchor.");
+ XCTAssertEqualObjects(layer.iconTranslationAnchor, constantExpression,
+ @"iconTranslationAnchor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.iconTranslationAnchor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = {{
+ { -INFINITY, mbgl::style::TranslateAnchorType::Viewport },
+ { 18, mbgl::style::TranslateAnchorType::Viewport },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
XCTAssertEqual(rawLayer->getIconTranslateAnchor(), propertyValue,
- @"Setting iconTranslationAnchor to a camera function should update icon-translate-anchor.");
- XCTAssertEqualObjects(layer.iconTranslationAnchor, functionStyleValue,
- @"iconTranslationAnchor should round-trip camera functions.");
+ @"Setting iconTranslationAnchor to a camera expression should update icon-translate-anchor.");
+ XCTAssertEqualObjects(layer.iconTranslationAnchor, functionExpression,
+ @"iconTranslationAnchor should round-trip camera expressions.");
layer.iconTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getIconTranslateAnchor().isUndefined(),
@"Unsetting iconTranslationAnchor should return icon-translate-anchor to the default value.");
- XCTAssertEqualObjects(layer.iconTranslationAnchor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.iconTranslationAnchor, defaultExpression,
@"iconTranslationAnchor should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.iconTranslationAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.iconTranslationAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// text-color
{
XCTAssertTrue(rawLayer->getTextColor().isUndefined(),
@"text-color should be unset initially.");
- MGLStyleValue<MGLColor *> *defaultStyleValue = layer.textColor;
+ NSExpression *defaultExpression = layer.textColor;
- MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.textColor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ layer.textColor = constantExpression;
mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getTextColor(), propertyValue,
- @"Setting textColor to a constant value should update text-color.");
- XCTAssertEqualObjects(layer.textColor, constantStyleValue,
- @"textColor should round-trip constant values.");
-
- MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textColor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ @"Setting textColor to a constant value expression should update text-color.");
+ XCTAssertEqualObjects(layer.textColor, constantExpression,
+ @"textColor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textColor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = {{
+ { -INFINITY, { 1, 0, 0, 1 } },
+ { 18, { 1, 0, 0, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
XCTAssertEqual(rawLayer->getTextColor(), propertyValue,
- @"Setting textColor to a camera function should update text-color.");
- XCTAssertEqualObjects(layer.textColor, functionStyleValue,
- @"textColor should round-trip camera functions.");
+ @"Setting textColor to a camera expression should update text-color.");
+ XCTAssertEqualObjects(layer.textColor, functionExpression,
+ @"textColor should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.textColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.textColor = functionExpression;
mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getTextColor(), propertyValue,
- @"Setting textColor to a source function should update text-color.");
- XCTAssertEqualObjects(layer.textColor, functionStyleValue,
- @"textColor should round-trip source functions.");
+ @"Setting textColor to a data expression should update text-color.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.textColor, pedanticFunctionExpression,
+ @"textColor should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.textColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.textColor = functionExpression;
std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -2043,15 +2264,16 @@
propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getTextColor(), propertyValue,
- @"Setting textColor to a composite function should update text-color.");
- XCTAssertEqualObjects(layer.textColor, functionStyleValue,
- @"textColor should round-trip composite functions.");
+ @"Setting textColor to a camera-data expression should update text-color.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.textColor, pedanticFunctionExpression,
+ @"textColor should round-trip camera-data expressions.");
layer.textColor = nil;
XCTAssertTrue(rawLayer->getTextColor().isUndefined(),
@"Unsetting textColor should return text-color to the default value.");
- XCTAssertEqualObjects(layer.textColor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textColor, defaultExpression,
@"textColor should return the default value after being unset.");
// Transition property test
layer.textColorTransition = transitionTest;
@@ -2068,40 +2290,45 @@
{
XCTAssertTrue(rawLayer->getTextHaloBlur().isUndefined(),
@"text-halo-blur should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textHaloBlur;
+ NSExpression *defaultExpression = layer.textHaloBlur;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.textHaloBlur = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.textHaloBlur = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue,
- @"Setting textHaloBlur to a constant value should update text-halo-blur.");
- XCTAssertEqualObjects(layer.textHaloBlur, constantStyleValue,
- @"textHaloBlur should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textHaloBlur = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting textHaloBlur to a constant value expression should update text-halo-blur.");
+ XCTAssertEqualObjects(layer.textHaloBlur, constantExpression,
+ @"textHaloBlur should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textHaloBlur = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue,
- @"Setting textHaloBlur to a camera function should update text-halo-blur.");
- XCTAssertEqualObjects(layer.textHaloBlur, functionStyleValue,
- @"textHaloBlur should round-trip camera functions.");
+ @"Setting textHaloBlur to a camera expression should update text-halo-blur.");
+ XCTAssertEqualObjects(layer.textHaloBlur, functionExpression,
+ @"textHaloBlur should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.textHaloBlur = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.textHaloBlur = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue,
- @"Setting textHaloBlur to a source function should update text-halo-blur.");
- XCTAssertEqualObjects(layer.textHaloBlur, functionStyleValue,
- @"textHaloBlur should round-trip source functions.");
+ @"Setting textHaloBlur to a data expression should update text-halo-blur.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.textHaloBlur, pedanticFunctionExpression,
+ @"textHaloBlur should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.textHaloBlur = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.textHaloBlur = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -2109,15 +2336,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue,
- @"Setting textHaloBlur to a composite function should update text-halo-blur.");
- XCTAssertEqualObjects(layer.textHaloBlur, functionStyleValue,
- @"textHaloBlur should round-trip composite functions.");
+ @"Setting textHaloBlur to a camera-data expression should update text-halo-blur.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.textHaloBlur, pedanticFunctionExpression,
+ @"textHaloBlur should round-trip camera-data expressions.");
layer.textHaloBlur = nil;
XCTAssertTrue(rawLayer->getTextHaloBlur().isUndefined(),
@"Unsetting textHaloBlur should return text-halo-blur to the default value.");
- XCTAssertEqualObjects(layer.textHaloBlur, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textHaloBlur, defaultExpression,
@"textHaloBlur should return the default value after being unset.");
// Transition property test
layer.textHaloBlurTransition = transitionTest;
@@ -2134,40 +2362,45 @@
{
XCTAssertTrue(rawLayer->getTextHaloColor().isUndefined(),
@"text-halo-color should be unset initially.");
- MGLStyleValue<MGLColor *> *defaultStyleValue = layer.textHaloColor;
+ NSExpression *defaultExpression = layer.textHaloColor;
- MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.textHaloColor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ layer.textHaloColor = constantExpression;
mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue,
- @"Setting textHaloColor to a constant value should update text-halo-color.");
- XCTAssertEqualObjects(layer.textHaloColor, constantStyleValue,
- @"textHaloColor should round-trip constant values.");
-
- MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textHaloColor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ @"Setting textHaloColor to a constant value expression should update text-halo-color.");
+ XCTAssertEqualObjects(layer.textHaloColor, constantExpression,
+ @"textHaloColor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"%@", [MGLColor redColor]];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textHaloColor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = {{
+ { -INFINITY, { 1, 0, 0, 1 } },
+ { 18, { 1, 0, 0, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue,
- @"Setting textHaloColor to a camera function should update text-halo-color.");
- XCTAssertEqualObjects(layer.textHaloColor, functionStyleValue,
- @"textHaloColor should round-trip camera functions.");
+ @"Setting textHaloColor to a camera expression should update text-halo-color.");
+ XCTAssertEqualObjects(layer.textHaloColor, functionExpression,
+ @"textHaloColor should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.textHaloColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.textHaloColor = functionExpression;
mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue,
- @"Setting textHaloColor to a source function should update text-halo-color.");
- XCTAssertEqualObjects(layer.textHaloColor, functionStyleValue,
- @"textHaloColor should round-trip source functions.");
+ @"Setting textHaloColor to a data expression should update text-halo-color.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.textHaloColor, pedanticFunctionExpression,
+ @"textHaloColor should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.textHaloColor = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.textHaloColor = functionExpression;
std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -2175,15 +2408,16 @@
propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue,
- @"Setting textHaloColor to a composite function should update text-halo-color.");
- XCTAssertEqualObjects(layer.textHaloColor, functionStyleValue,
- @"textHaloColor should round-trip composite functions.");
+ @"Setting textHaloColor to a camera-data expression should update text-halo-color.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.textHaloColor, pedanticFunctionExpression,
+ @"textHaloColor should round-trip camera-data expressions.");
layer.textHaloColor = nil;
XCTAssertTrue(rawLayer->getTextHaloColor().isUndefined(),
@"Unsetting textHaloColor should return text-halo-color to the default value.");
- XCTAssertEqualObjects(layer.textHaloColor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textHaloColor, defaultExpression,
@"textHaloColor should return the default value after being unset.");
// Transition property test
layer.textHaloColorTransition = transitionTest;
@@ -2200,40 +2434,45 @@
{
XCTAssertTrue(rawLayer->getTextHaloWidth().isUndefined(),
@"text-halo-width should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textHaloWidth;
+ NSExpression *defaultExpression = layer.textHaloWidth;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.textHaloWidth = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.textHaloWidth = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue,
- @"Setting textHaloWidth to a constant value should update text-halo-width.");
- XCTAssertEqualObjects(layer.textHaloWidth, constantStyleValue,
- @"textHaloWidth should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textHaloWidth = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting textHaloWidth to a constant value expression should update text-halo-width.");
+ XCTAssertEqualObjects(layer.textHaloWidth, constantExpression,
+ @"textHaloWidth should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textHaloWidth = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue,
- @"Setting textHaloWidth to a camera function should update text-halo-width.");
- XCTAssertEqualObjects(layer.textHaloWidth, functionStyleValue,
- @"textHaloWidth should round-trip camera functions.");
+ @"Setting textHaloWidth to a camera expression should update text-halo-width.");
+ XCTAssertEqualObjects(layer.textHaloWidth, functionExpression,
+ @"textHaloWidth should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.textHaloWidth = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.textHaloWidth = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue,
- @"Setting textHaloWidth to a source function should update text-halo-width.");
- XCTAssertEqualObjects(layer.textHaloWidth, functionStyleValue,
- @"textHaloWidth should round-trip source functions.");
+ @"Setting textHaloWidth to a data expression should update text-halo-width.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.textHaloWidth, pedanticFunctionExpression,
+ @"textHaloWidth should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.textHaloWidth = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.textHaloWidth = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -2241,15 +2480,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue,
- @"Setting textHaloWidth to a composite function should update text-halo-width.");
- XCTAssertEqualObjects(layer.textHaloWidth, functionStyleValue,
- @"textHaloWidth should round-trip composite functions.");
+ @"Setting textHaloWidth to a camera-data expression should update text-halo-width.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.textHaloWidth, pedanticFunctionExpression,
+ @"textHaloWidth should round-trip camera-data expressions.");
layer.textHaloWidth = nil;
XCTAssertTrue(rawLayer->getTextHaloWidth().isUndefined(),
@"Unsetting textHaloWidth should return text-halo-width to the default value.");
- XCTAssertEqualObjects(layer.textHaloWidth, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textHaloWidth, defaultExpression,
@"textHaloWidth should return the default value after being unset.");
// Transition property test
layer.textHaloWidthTransition = transitionTest;
@@ -2266,40 +2506,45 @@
{
XCTAssertTrue(rawLayer->getTextOpacity().isUndefined(),
@"text-opacity should be unset initially.");
- MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textOpacity;
+ NSExpression *defaultExpression = layer.textOpacity;
- MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.textOpacity = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ layer.textOpacity = constantExpression;
mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue,
- @"Setting textOpacity to a constant value should update text-opacity.");
- XCTAssertEqualObjects(layer.textOpacity, constantStyleValue,
- @"textOpacity should round-trip constant values.");
-
- MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textOpacity = functionStyleValue;
-
- mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ @"Setting textOpacity to a constant value expression should update text-opacity.");
+ XCTAssertEqualObjects(layer.textOpacity, constantExpression,
+ @"textOpacity should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"0xff"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textOpacity = functionExpression;
+
+ mbgl::style::IntervalStops<float> intervalStops = {{
+ { -INFINITY, 0xff },
+ { 18, 0xff },
+ }};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue,
- @"Setting textOpacity to a camera function should update text-opacity.");
- XCTAssertEqualObjects(layer.textOpacity, functionStyleValue,
- @"textOpacity should round-trip camera functions.");
+ @"Setting textOpacity to a camera expression should update text-opacity.");
+ XCTAssertEqualObjects(layer.textOpacity, functionExpression,
+ @"textOpacity should round-trip camera expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
- layer.textOpacity = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.textOpacity = functionExpression;
mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue,
- @"Setting textOpacity to a source function should update text-opacity.");
- XCTAssertEqualObjects(layer.textOpacity, functionStyleValue,
- @"textOpacity should round-trip source functions.");
+ @"Setting textOpacity to a data expression should update text-opacity.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.textOpacity, pedanticFunctionExpression,
+ @"textOpacity should round-trip data expressions.");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
- layer.textOpacity = functionStyleValue;
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.textOpacity = functionExpression;
std::map<float, float> innerStops { {18, 0xff} };
mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
@@ -2307,15 +2552,16 @@
propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue,
- @"Setting textOpacity to a composite function should update text-opacity.");
- XCTAssertEqualObjects(layer.textOpacity, functionStyleValue,
- @"textOpacity should round-trip composite functions.");
+ @"Setting textOpacity to a camera-data expression should update text-opacity.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.textOpacity, pedanticFunctionExpression,
+ @"textOpacity should round-trip camera-data expressions.");
layer.textOpacity = nil;
XCTAssertTrue(rawLayer->getTextOpacity().isUndefined(),
@"Unsetting textOpacity should return text-opacity to the default value.");
- XCTAssertEqualObjects(layer.textOpacity, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textOpacity, defaultExpression,
@"textOpacity should return the default value after being unset.");
// Transition property test
layer.textOpacityTransition = transitionTest;
@@ -2332,84 +2578,94 @@
{
XCTAssertTrue(rawLayer->getTextTranslate().isUndefined(),
@"text-translate should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.textTranslation;
+ NSExpression *defaultExpression = layer.textTranslation;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"%@",
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
- layer.textTranslation = constantStyleValue;
+ layer.textTranslation = constantExpression;
mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getTextTranslate(), propertyValue,
- @"Setting textTranslation to a constant value should update text-translate.");
- XCTAssertEqualObjects(layer.textTranslation, constantStyleValue,
- @"textTranslation should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textTranslation = functionStyleValue;
-
- mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} };
+ @"Setting textTranslation to a constant value expression should update text-translate.");
+ XCTAssertEqualObjects(layer.textTranslation, constantExpression,
+ @"textTranslation should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"{1, 1}"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textTranslation = functionExpression;
+
+ mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = {{
+ { -INFINITY, { 1, 1 } },
+ { 18, { 1, 1 } },
+ }};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
XCTAssertEqual(rawLayer->getTextTranslate(), propertyValue,
- @"Setting textTranslation to a camera function should update text-translate.");
- XCTAssertEqualObjects(layer.textTranslation, functionStyleValue,
- @"textTranslation should round-trip camera functions.");
+ @"Setting textTranslation to a camera expression should update text-translate.");
+ XCTAssertEqualObjects(layer.textTranslation, functionExpression,
+ @"textTranslation should round-trip camera expressions.");
layer.textTranslation = nil;
XCTAssertTrue(rawLayer->getTextTranslate().isUndefined(),
@"Unsetting textTranslation should return text-translate to the default value.");
- XCTAssertEqualObjects(layer.textTranslation, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textTranslation, defaultExpression,
@"textTranslation should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.textTranslation = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.textTranslation = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
// text-translate-anchor
{
XCTAssertTrue(rawLayer->getTextTranslateAnchor().isUndefined(),
@"text-translate-anchor should be unset initially.");
- MGLStyleValue<NSValue *> *defaultStyleValue = layer.textTranslationAnchor;
+ NSExpression *defaultExpression = layer.textTranslationAnchor;
- MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextTranslationAnchor:MGLTextTranslationAnchorViewport]];
- layer.textTranslationAnchor = constantStyleValue;
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ layer.textTranslationAnchor = constantExpression;
mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
XCTAssertEqual(rawLayer->getTextTranslateAnchor(), propertyValue,
- @"Setting textTranslationAnchor to a constant value should update text-translate-anchor.");
- XCTAssertEqualObjects(layer.textTranslationAnchor, constantStyleValue,
- @"textTranslationAnchor should round-trip constant values.");
-
- MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
- layer.textTranslationAnchor = functionStyleValue;
-
- mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} };
+ @"Setting textTranslationAnchor to a constant value expression should update text-translate-anchor.");
+ XCTAssertEqualObjects(layer.textTranslationAnchor, constantExpression,
+ @"textTranslationAnchor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"'viewport'"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textTranslationAnchor = functionExpression;
+
+ mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = {{
+ { -INFINITY, mbgl::style::TranslateAnchorType::Viewport },
+ { 18, mbgl::style::TranslateAnchorType::Viewport },
+ }};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
XCTAssertEqual(rawLayer->getTextTranslateAnchor(), propertyValue,
- @"Setting textTranslationAnchor to a camera function should update text-translate-anchor.");
- XCTAssertEqualObjects(layer.textTranslationAnchor, functionStyleValue,
- @"textTranslationAnchor should round-trip camera functions.");
+ @"Setting textTranslationAnchor to a camera expression should update text-translate-anchor.");
+ XCTAssertEqualObjects(layer.textTranslationAnchor, functionExpression,
+ @"textTranslationAnchor should round-trip camera expressions.");
layer.textTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getTextTranslateAnchor().isUndefined(),
@"Unsetting textTranslationAnchor should return text-translate-anchor to the default value.");
- XCTAssertEqualObjects(layer.textTranslationAnchor, defaultStyleValue,
+ XCTAssertEqualObjects(layer.textTranslationAnchor, defaultExpression,
@"textTranslationAnchor should return the default value after being unset.");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.textTranslationAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.textTranslationAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
}
diff --git a/platform/darwin/test/MGLTileSetTests.mm b/platform/darwin/test/MGLTileSetTests.mm
index 4d5e1fcd05..2319f66447 100644
--- a/platform/darwin/test/MGLTileSetTests.mm
+++ b/platform/darwin/test/MGLTileSetTests.mm
@@ -66,8 +66,16 @@
// when the tile set has attribution infos
MGLAttributionInfo *mapboxInfo = [[MGLAttributionInfo alloc] initWithTitle:[[NSAttributedString alloc] initWithString:@"Mapbox"]
URL:[NSURL URLWithString:@"https://www.mapbox.com/"]];
+#if TARGET_OS_IPHONE
+ UIColor *redColor = [UIColor redColor];
+#else
+ // CSS uses the sRGB color space. In macOS 10.12 Sierra and below,
+ // -[NSColor redColor] is in the calibrated RGB space and has a slightly
+ // different sRGB value than on iOS and macOS 10.13 High Sierra.
+ NSColor *redColor = [NSColor colorWithSRGBRed:1 green:0 blue:0 alpha:1];
+#endif
NSAttributedString *gl = [[NSAttributedString alloc] initWithString:@"GL" attributes:@{
- NSBackgroundColorAttributeName: [MGLColor redColor],
+ NSBackgroundColorAttributeName: redColor,
}];
MGLAttributionInfo *glInfo = [[MGLAttributionInfo alloc] initWithTitle:gl URL:nil];
tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, @{
@@ -82,7 +90,7 @@
#else
NSString *html = (@"<font face=\"Helvetica\" size=\"3\" style=\"font: 12.0px Helvetica\">"
@"<a href=\"https://www.mapbox.com/\">Mapbox</a> </font>"
- @"<font face=\"Helvetica\" size=\"3\" style=\"font: 12.0px Helvetica; background-color: #ff2600\">GL</font>\n");
+ @"<font face=\"Helvetica\" size=\"3\" style=\"font: 12.0px Helvetica; background-color: #ff0000\">GL</font>\n");
#endif
XCTAssertEqualObjects(@(tileSet.attribution.c_str()), html);
@@ -102,6 +110,23 @@
// the scheme is reflected by the mbgl tileset
XCTAssertEqual(tileSet.scheme, mbgl::Tileset::Scheme::TMS);
+
+ // when the dem enciding is changed using an NSNumber
+ tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, @{
+ MGLTileSourceOptionDEMEncoding: @(MGLDEMEncodingTerrarium),
+ });
+
+ // the encoding is reflected by the mbgl tileset
+ XCTAssertEqual(tileSet.encoding, mbgl::Tileset::DEMEncoding::Terrarium);
+
+ // when the dem enciding is changed using an NSValue
+ MGLDEMEncoding terrarium = MGLDEMEncodingTerrarium;
+ tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, @{
+ MGLTileSourceOptionDEMEncoding: [NSValue value:&terrarium withObjCType:@encode(MGLDEMEncoding)],
+ });
+
+ // the encoding is reflected by the mbgl tileset
+ XCTAssertEqual(tileSet.encoding, mbgl::Tileset::DEMEncoding::Terrarium);
}
- (void)testInvalidTileSet {
diff --git a/platform/darwin/test/test-Bridging-Header.h b/platform/darwin/test/test-Bridging-Header.h
index 5d23e9d6c5..1b2cb5d6d0 100644
--- a/platform/darwin/test/test-Bridging-Header.h
+++ b/platform/darwin/test/test-Bridging-Header.h
@@ -1,4 +1,4 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
-#import "MGLStyleValueTests.h"
+