diff --git a/platform/darwin/src/MGLFillStyleLayer.h b/platform/darwin/src/MGLFillStyleLayer.h index b6f0e9bd0..931a0abdd 100644 --- a/platform/darwin/src/MGLFillStyleLayer.h +++ b/platform/darwin/src/MGLFillStyleLayer.h @@ -76,6 +76,23 @@ MGL_EXPORT */ - (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source; +#pragma mark - Accessing the Layout Attributes + +/** + Sorts features in ascending order based on this value. Features with a higher + sort key will appear above features with a lower sort key. + + 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) NSExpression *fillSortKey; + #pragma mark - Accessing the Paint Attributes /** diff --git a/platform/darwin/src/MGLFillStyleLayer.mm b/platform/darwin/src/MGLFillStyleLayer.mm index d8c5516f3..a26a16c4d 100644 --- a/platform/darwin/src/MGLFillStyleLayer.mm +++ b/platform/darwin/src/MGLFillStyleLayer.mm @@ -81,6 +81,26 @@ namespace mbgl { return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()]; } +#pragma mark - Accessing the Layout Attributes + +- (void)setFillSortKey:(NSExpression *)fillSortKey { + MGLAssertStyleLayerIsValid(); + MGLLogDebug(@"Setting fillSortKey: %@", fillSortKey); + + auto mbglValue = MGLStyleValueTransformer().toPropertyValue>(fillSortKey, true); + self.rawLayer->setFillSortKey(mbglValue); +} + +- (NSExpression *)fillSortKey { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getFillSortKey(); + if (propertyValue.isUndefined()) { + propertyValue = self.rawLayer->getDefaultFillSortKey(); + } + return MGLStyleValueTransformer().toExpression(propertyValue); +} + #pragma mark - Accessing the Paint Attributes - (void)setFillAntialiased:(NSExpression *)fillAntialiased { diff --git a/platform/darwin/src/MGLLineStyleLayer.h b/platform/darwin/src/MGLLineStyleLayer.h index 3400f7e75..00856e9d2 100644 --- a/platform/darwin/src/MGLLineStyleLayer.h +++ b/platform/darwin/src/MGLLineStyleLayer.h @@ -229,6 +229,21 @@ MGL_EXPORT */ @property (nonatomic, null_resettable) NSExpression *lineRoundLimit; +/** + Sorts features in ascending order based on this value. Features with a higher + sort key will appear above features with a lower sort key. + + 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) NSExpression *lineSortKey; + #pragma mark - Accessing the Paint Attributes /** diff --git a/platform/darwin/src/MGLLineStyleLayer.mm b/platform/darwin/src/MGLLineStyleLayer.mm index 62d778a6f..33504ba09 100644 --- a/platform/darwin/src/MGLLineStyleLayer.mm +++ b/platform/darwin/src/MGLLineStyleLayer.mm @@ -167,6 +167,24 @@ namespace mbgl { return MGLStyleValueTransformer().toExpression(propertyValue); } +- (void)setLineSortKey:(NSExpression *)lineSortKey { + MGLAssertStyleLayerIsValid(); + MGLLogDebug(@"Setting lineSortKey: %@", lineSortKey); + + auto mbglValue = MGLStyleValueTransformer().toPropertyValue>(lineSortKey, true); + self.rawLayer->setLineSortKey(mbglValue); +} + +- (NSExpression *)lineSortKey { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getLineSortKey(); + if (propertyValue.isUndefined()) { + propertyValue = self.rawLayer->getDefaultLineSortKey(); + } + return MGLStyleValueTransformer().toExpression(propertyValue); +} + #pragma mark - Accessing the Paint Attributes - (void)setLineBlur:(NSExpression *)lineBlur { diff --git a/platform/darwin/test/MGLFillStyleLayerTests.mm b/platform/darwin/test/MGLFillStyleLayerTests.mm index e37bd537a..60e4d9609 100644 --- a/platform/darwin/test/MGLFillStyleLayerTests.mm +++ b/platform/darwin/test/MGLFillStyleLayerTests.mm @@ -49,6 +49,75 @@ MGLTransition transitionTest = MGLTransitionMake(5, 4); + // fill-sort-key + { + XCTAssertTrue(rawLayer->getFillSortKey().isUndefined(), + @"fill-sort-key should be unset initially."); + NSExpression *defaultExpression = layer.fillSortKey; + + NSExpression *constantExpression = [NSExpression expressionWithFormat:@"1"]; + layer.fillSortKey = constantExpression; + mbgl::style::PropertyValue propertyValue = { 1.0 }; + XCTAssertEqual(rawLayer->getFillSortKey(), propertyValue, + @"Setting fillSortKey to a constant value expression should update fill-sort-key."); + XCTAssertEqualObjects(layer.fillSortKey, constantExpression, + @"fillSortKey should round-trip constant value expressions."); + + constantExpression = [NSExpression expressionWithFormat:@"1"]; + NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}]; + layer.fillSortKey = functionExpression; + + { + using namespace mbgl::style::expression::dsl; + propertyValue = mbgl::style::PropertyExpression( + step(zoom(), literal(1.0), 18.0, literal(1.0)) + ); + } + + XCTAssertEqual(rawLayer->getFillSortKey(), propertyValue, + @"Setting fillSortKey to a camera expression should update fill-sort-key."); + XCTAssertEqualObjects(layer.fillSortKey, functionExpression, + @"fillSortKey should round-trip camera expressions."); + + functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}]; + layer.fillSortKey = functionExpression; + + { + using namespace mbgl::style::expression::dsl; + propertyValue = mbgl::style::PropertyExpression( + interpolate(linear(), number(get("keyName")), 18.0, literal(1.0)) + ); + } + + XCTAssertEqual(rawLayer->getFillSortKey(), propertyValue, + @"Setting fillSortKey to a data expression should update fill-sort-key."); + NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}]; + XCTAssertEqualObjects(layer.fillSortKey, pedanticFunctionExpression, + @"fillSortKey should round-trip data expressions."); + + functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}]; + layer.fillSortKey = functionExpression; + + { + using namespace mbgl::style::expression::dsl; + propertyValue = mbgl::style::PropertyExpression( + interpolate(linear(), zoom(), 10.0, interpolate(linear(), number(get("keyName")), 18.0, literal(1.0))) + ); + } + + XCTAssertEqual(rawLayer->getFillSortKey(), propertyValue, + @"Setting fillSortKey to a camera-data expression should update fill-sort-key."); + pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}]; + XCTAssertEqualObjects(layer.fillSortKey, pedanticFunctionExpression, + @"fillSortKey should round-trip camera-data expressions."); + + layer.fillSortKey = nil; + XCTAssertTrue(rawLayer->getFillSortKey().isUndefined(), + @"Unsetting fillSortKey should return fill-sort-key to the default value."); + XCTAssertEqualObjects(layer.fillSortKey, defaultExpression, + @"fillSortKey should return the default value after being unset."); + } + // fill-antialias { XCTAssertTrue(rawLayer->getFillAntialias().isUndefined(), @@ -470,6 +539,7 @@ } - (void)testPropertyNames { + [self testPropertyName:@"fill-sort-key" isBoolean:NO]; [self testPropertyName:@"is-fill-antialiased" isBoolean:YES]; [self testPropertyName:@"fill-color" isBoolean:NO]; [self testPropertyName:@"fill-opacity" isBoolean:NO]; diff --git a/platform/darwin/test/MGLLineStyleLayerTests.mm b/platform/darwin/test/MGLLineStyleLayerTests.mm index 46f040b60..6d21d17f0 100644 --- a/platform/darwin/test/MGLLineStyleLayerTests.mm +++ b/platform/darwin/test/MGLLineStyleLayerTests.mm @@ -219,6 +219,75 @@ 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-sort-key + { + XCTAssertTrue(rawLayer->getLineSortKey().isUndefined(), + @"line-sort-key should be unset initially."); + NSExpression *defaultExpression = layer.lineSortKey; + + NSExpression *constantExpression = [NSExpression expressionWithFormat:@"1"]; + layer.lineSortKey = constantExpression; + mbgl::style::PropertyValue propertyValue = { 1.0 }; + XCTAssertEqual(rawLayer->getLineSortKey(), propertyValue, + @"Setting lineSortKey to a constant value expression should update line-sort-key."); + XCTAssertEqualObjects(layer.lineSortKey, constantExpression, + @"lineSortKey should round-trip constant value expressions."); + + constantExpression = [NSExpression expressionWithFormat:@"1"]; + NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}]; + layer.lineSortKey = functionExpression; + + { + using namespace mbgl::style::expression::dsl; + propertyValue = mbgl::style::PropertyExpression( + step(zoom(), literal(1.0), 18.0, literal(1.0)) + ); + } + + XCTAssertEqual(rawLayer->getLineSortKey(), propertyValue, + @"Setting lineSortKey to a camera expression should update line-sort-key."); + XCTAssertEqualObjects(layer.lineSortKey, functionExpression, + @"lineSortKey should round-trip camera expressions."); + + functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}]; + layer.lineSortKey = functionExpression; + + { + using namespace mbgl::style::expression::dsl; + propertyValue = mbgl::style::PropertyExpression( + interpolate(linear(), number(get("keyName")), 18.0, literal(1.0)) + ); + } + + XCTAssertEqual(rawLayer->getLineSortKey(), propertyValue, + @"Setting lineSortKey to a data expression should update line-sort-key."); + NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}]; + XCTAssertEqualObjects(layer.lineSortKey, pedanticFunctionExpression, + @"lineSortKey should round-trip data expressions."); + + functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}]; + layer.lineSortKey = functionExpression; + + { + using namespace mbgl::style::expression::dsl; + propertyValue = mbgl::style::PropertyExpression( + interpolate(linear(), zoom(), 10.0, interpolate(linear(), number(get("keyName")), 18.0, literal(1.0))) + ); + } + + XCTAssertEqual(rawLayer->getLineSortKey(), propertyValue, + @"Setting lineSortKey to a camera-data expression should update line-sort-key."); + pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}]; + XCTAssertEqualObjects(layer.lineSortKey, pedanticFunctionExpression, + @"lineSortKey should round-trip camera-data expressions."); + + layer.lineSortKey = nil; + XCTAssertTrue(rawLayer->getLineSortKey().isUndefined(), + @"Unsetting lineSortKey should return line-sort-key to the default value."); + XCTAssertEqualObjects(layer.lineSortKey, defaultExpression, + @"lineSortKey should return the default value after being unset."); + } + // line-blur { XCTAssertTrue(rawLayer->getLineBlur().isUndefined(), @@ -878,6 +947,7 @@ [self testPropertyName:@"line-join" isBoolean:NO]; [self testPropertyName:@"line-miter-limit" isBoolean:NO]; [self testPropertyName:@"line-round-limit" isBoolean:NO]; + [self testPropertyName:@"line-sort-key" isBoolean:NO]; [self testPropertyName:@"line-blur" isBoolean:NO]; [self testPropertyName:@"line-color" isBoolean:NO]; [self testPropertyName:@"line-dash-pattern" isBoolean:NO]; diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 4b8d449e8..e185ddee2 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -4,6 +4,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT ## master +* Added the `MGLLineStyleLayer.lineSortKey` and `MGLFillStyleLayer.fillSortKey` properties. ([#179](https://github.com/mapbox/mapbox-gl-native-ios/pull/179)) * The `-[MGLStyle localizeLabelsIntoLocale:]` and `-[NSExpression mgl_expressionLocalizedIntoLocale:]` methods can now localize text into Traditional Chinese and Vietnamese. ([#173](https://github.com/mapbox/mapbox-gl-native-ios/pull/173)) ## 5.7.0 - February 13, 2020 diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 48458d614..97e944329 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -7,6 +7,7 @@ * Added the `-[MGLMapViewDelegate mapView:shouldRemoveStyleImage:]` method for optimizing style image caching. ([#14769](https://github.com/mapbox/mapbox-gl-native/pull/14769)) * Added the `image` expression function for converting an image name into a style image. Use this function in expressions in style JSON or with the `MGL_FUNCTION()` syntax in an `NSExpression` format string. ([#15877](https://github.com/mapbox/mapbox-gl-native/pull/15877)) * Added the `MGLSymbolStyleLayer.textWritingModes` layout property. This property can be set to `MGLTextWritingModeHorizontal` or `MGLTextWritingModeVertical`. ([#14932](https://github.com/mapbox/mapbox-gl-native/pull/14932)) +* Added the `MGLLineStyleLayer.lineSortKey` and `MGLFillStyleLayer.fillSortKey` properties. ([#179](https://github.com/mapbox/mapbox-gl-native-ios/pull/179)) * The `MGLIdeographicFontFamilyName` Info.plist key now also accepts an array of font family names, to customize font fallback behavior. It can also be set to a Boolean value of `NO` to force the SDK to typeset CJK characters in a remote font specified by `MGLSymbolStyleLayer.textFontNames`. ([#14862](https://github.com/mapbox/mapbox-gl-native/pull/14862)) * The `-[MGLStyle localizeLabelsIntoLocale:]` and `-[NSExpression mgl_expressionLocalizedIntoLocale:]` methods can now localize text into Traditional Chinese and Vietnamese. ([#173](https://github.com/mapbox/mapbox-gl-native-ios/pull/173)) * Fixed crashes triggered when `MGLSource` and `MGLStyleLayer` objects are accessed after having been invalidated after a style change. ([#15539](https://github.com/mapbox/mapbox-gl-native/pull/15539))