diff --git a/circle.yml b/circle.yml index ef7490862f..1fec540859 100644 --- a/circle.yml +++ b/circle.yml @@ -504,9 +504,9 @@ jobs: - run: name: Lint plist files command: make macos-lint - #- run: - # name: Nitpick Darwin code generation - # command: scripts/nitpick/generated-code.js darwin + - run: + name: Nitpick Darwin code generation + command: scripts/nitpick/generated-code.js darwin - save-dependencies - store_artifacts: path: test/fixtures diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js index bd5adb9685..9b164f2f4d 100755 --- a/platform/darwin/scripts/generate-style-code.js +++ b/platform/darwin/scripts/generate-style-code.js @@ -15,11 +15,6 @@ const suffix = 'StyleLayer'; let spec = _.merge(require('../../../scripts/style-spec'), require('./style-spec-overrides-v8.json')); -// FIXME: https://github.com/mapbox/mapbox-gl-native/issues/15008 -delete spec.layout_circle["circle-sort-key"] -delete spec.layout_line["line-sort-key"] -delete spec.layout_fill["fill-sort-key"] - class ConventionOverride { constructor(val) { if (typeof val === 'string') { diff --git a/platform/darwin/src/MGLFillStyleLayer.h b/platform/darwin/src/MGLFillStyleLayer.h index b6f0e9bd06..931a0abddf 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 d8c5516f3a..a26a16c4d1 100644 --- a/platform/darwin/src/MGLFillStyleLayer.mm +++ b/platform/darwin/src/MGLFillStyleLayer.mm @@ -81,6 +81,26 @@ - (NSPredicate *)predicate 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 3400f7e75b..00856e9d20 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 62d778a6f3..33504ba09b 100644 --- a/platform/darwin/src/MGLLineStyleLayer.mm +++ b/platform/darwin/src/MGLLineStyleLayer.mm @@ -167,6 +167,24 @@ - (NSExpression *)lineRoundLimit { 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 e37bd537a7..60e4d96099 100644 --- a/platform/darwin/test/MGLFillStyleLayerTests.mm +++ b/platform/darwin/test/MGLFillStyleLayerTests.mm @@ -49,6 +49,75 @@ - (void)testProperties { 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)testProperties { } - (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 46f040b601..6d21d17f09 100644 --- a/platform/darwin/test/MGLLineStyleLayerTests.mm +++ b/platform/darwin/test/MGLLineStyleLayerTests.mm @@ -219,6 +219,75 @@ - (void)testProperties { 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 @@ - (void)testPropertyNames { [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 4b8d449e8c..e185ddee29 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 48458d614d..97e9443295 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)) diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index 0aedba909b..40818500f3 100755 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -6,11 +6,6 @@ const ejs = require('ejs'); const spec = require('./style-spec'); const colorParser = require('csscolorparser'); -// FIXME: https://github.com/mapbox/mapbox-gl-native/issues/15008 -delete spec.layout_circle["circle-sort-key"] -delete spec.layout_line["line-sort-key"] -delete spec.layout_fill["fill-sort-key"] - require('./style-code'); function parseCSSColor(str) { diff --git a/scripts/style-spec.js b/scripts/style-spec.js index 8a9c9d4144..374c3bcb6e 100644 --- a/scripts/style-spec.js +++ b/scripts/style-spec.js @@ -1 +1,4 @@ -var spec = module.exports = require('../mapbox-gl-js/src/style-spec/reference/v8'); +var spec = module.exports = require('../vendor/mapbox-gl-native/mapbox-gl-js/src/style-spec/reference/v8'); + +// FIXME: https://github.com/mapbox/mapbox-gl-native/issues/15008 +delete spec.layout_circle["circle-sort-key"];