From fd7b289271ffcdfdc62b1c115e768c6fdec82337 Mon Sep 17 00:00:00 2001 From: Jesse Bounds Date: Wed, 4 Jan 2017 07:35:25 -0800 Subject: [PATCH] [ios, macos] Add support for data-driven property functions --- .../mbgl/style/data_driven_property_value.hpp | 5 + platform/darwin/src/MGLBackgroundStyleLayer.h | 14 +- .../darwin/src/MGLBackgroundStyleLayer.mm | 19 +- platform/darwin/src/MGLCircleStyleLayer.h | 50 +- platform/darwin/src/MGLCircleStyleLayer.mm | 80 +- platform/darwin/src/MGLFillStyleLayer.h | 38 +- platform/darwin/src/MGLFillStyleLayer.mm | 49 +- platform/darwin/src/MGLLineStyleLayer.h | 64 +- platform/darwin/src/MGLLineStyleLayer.mm | 98 +- platform/darwin/src/MGLRasterStyleLayer.h | 26 +- platform/darwin/src/MGLRasterStyleLayer.mm | 49 +- platform/darwin/src/MGLStyleLayer.mm.ejs | 52 +- platform/darwin/src/MGLStyleValue.h | 144 +- platform/darwin/src/MGLStyleValue.mm | 214 ++- platform/darwin/src/MGLStyleValue_Private.h | 687 +++++++- platform/darwin/src/MGLSymbolStyleLayer.h | 314 ++-- platform/darwin/src/MGLSymbolStyleLayer.mm | 296 +++- .../test/MGLBackgroundStyleLayerTests.mm | 92 +- .../darwin/test/MGLCircleStyleLayerTests.mm | 469 +++-- .../darwin/test/MGLFillStyleLayerTests.mm | 291 ++-- .../darwin/test/MGLLineStyleLayerTests.mm | 549 +++--- .../darwin/test/MGLRasterStyleLayerTests.mm | 198 +-- .../darwin/test/MGLStyleLayerTests.mm.ejs | 66 +- platform/darwin/test/MGLStyleValueTests.swift | 286 ++- .../darwin/test/MGLSymbolStyleLayerTests.mm | 1528 +++++++++-------- platform/ios/app/MBXViewController.m | 132 +- platform/ios/ios.xcodeproj/project.pbxproj | 2 +- platform/macos/app/MapDocument.m | 5 +- 28 files changed, 3891 insertions(+), 1926 deletions(-) diff --git a/include/mbgl/style/data_driven_property_value.hpp b/include/mbgl/style/data_driven_property_value.hpp index 4653224f15b..3f9ac694363 100644 --- a/include/mbgl/style/data_driven_property_value.hpp +++ b/include/mbgl/style/data_driven_property_value.hpp @@ -26,6 +26,11 @@ class DataDrivenPropertyValue { return lhs.value == rhs.value; } + friend bool operator!=(const DataDrivenPropertyValue& lhs, + const DataDrivenPropertyValue& rhs) { + return !(lhs == rhs); + } + public: DataDrivenPropertyValue() = default; DataDrivenPropertyValue( T v) : value(std::move(v)) {} diff --git a/platform/darwin/src/MGLBackgroundStyleLayer.h b/platform/darwin/src/MGLBackgroundStyleLayer.h index 60090ebfef4..02d5faff433 100644 --- a/platform/darwin/src/MGLBackgroundStyleLayer.h +++ b/platform/darwin/src/MGLBackgroundStyleLayer.h @@ -13,11 +13,11 @@ NS_ASSUME_NONNULL_BEGIN 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. - + A 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. - + If 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. */ @@ -31,11 +31,11 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** The color with which the background will be drawn. - + The default value of this property is an `MGLStyleValue` object containing `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. */ @@ -43,11 +43,11 @@ MGL_EXPORT #else /** The color with which the background will be drawn. - + The default value of this property is an `MGLStyleValue` object containing `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. */ @@ -56,7 +56,7 @@ MGL_EXPORT /** 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. diff --git a/platform/darwin/src/MGLBackgroundStyleLayer.mm b/platform/darwin/src/MGLBackgroundStyleLayer.mm index 9c359c2db69..166c5926f53 100644 --- a/platform/darwin/src/MGLBackgroundStyleLayer.mm +++ b/platform/darwin/src/MGLBackgroundStyleLayer.mm @@ -86,28 +86,34 @@ - (void)removeFromMapView:(MGLMapView *)mapView - (void)setBackgroundColor:(MGLStyleValue *)backgroundColor { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(backgroundColor); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(backgroundColor); self.rawLayer->setBackgroundColor(mbglValue); } - (MGLStyleValue *)backgroundColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getBackgroundColor() ?: self.rawLayer->getDefaultBackgroundColor(); + auto propertyValue = self.rawLayer->getBackgroundColor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultBackgroundColor()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setBackgroundOpacity:(MGLStyleValue *)backgroundOpacity { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(backgroundOpacity); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(backgroundOpacity); self.rawLayer->setBackgroundOpacity(mbglValue); } - (MGLStyleValue *)backgroundOpacity { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getBackgroundOpacity() ?: self.rawLayer->getDefaultBackgroundOpacity(); + auto propertyValue = self.rawLayer->getBackgroundOpacity(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultBackgroundOpacity()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -121,7 +127,10 @@ - (void)setBackgroundPattern:(MGLStyleValue *)backgroundPattern { - (MGLStyleValue *)backgroundPattern { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getBackgroundPattern() ?: self.rawLayer->getDefaultBackgroundPattern(); + auto propertyValue = self.rawLayer->getBackgroundPattern(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultBackgroundPattern()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } diff --git a/platform/darwin/src/MGLCircleStyleLayer.h b/platform/darwin/src/MGLCircleStyleLayer.h index 5f6fa313fbd..8d3497e423b 100644 --- a/platform/darwin/src/MGLCircleStyleLayer.h +++ b/platform/darwin/src/MGLCircleStyleLayer.h @@ -44,12 +44,12 @@ typedef NS_ENUM(NSUInteger, MGLCircleTranslationAnchor) { /** An `MGLCircleStyleLayer` is a style layer that renders one or more filled 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. - + 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, use many-sided regular polygons and configure their appearance using an @@ -84,7 +84,7 @@ 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. @@ -94,7 +94,7 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** The fill color of the circle. - + The default value of this property is an `MGLStyleValue` object containing `UIColor.blackColor`. Set this property to `nil` to reset it to the default value. @@ -103,7 +103,7 @@ MGL_EXPORT #else /** The fill color of the circle. - + The default value of this property is an `MGLStyleValue` object containing `NSColor.blackColor`. Set this property to `nil` to reset it to the default value. @@ -113,7 +113,7 @@ 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. @@ -122,9 +122,9 @@ MGL_EXPORT /** 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. @@ -133,11 +133,11 @@ 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. - + This attribute corresponds to the circle-pitch-scale layout property in the Mapbox Style Specification. @@ -149,7 +149,7 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** The stroke color of the circle. - + The default value of this property is an `MGLStyleValue` object containing `UIColor.blackColor`. Set this property to `nil` to reset it to the default value. @@ -158,7 +158,7 @@ MGL_EXPORT #else /** The stroke color of the circle. - + The default value of this property is an `MGLStyleValue` object containing `NSColor.blackColor`. Set this property to `nil` to reset it to the default value. @@ -168,7 +168,7 @@ 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. @@ -177,10 +177,10 @@ MGL_EXPORT /** The width of the circle's stroke. Strokes are placed outside of the - "circle-radius". - + `circleRadius`. + 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. @@ -190,13 +190,13 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** The geometry's offset. - + This property is measured in points. - + The default value of this property is an `MGLStyleValue` object containing 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. - + This attribute corresponds to the circle-translate layout property in the Mapbox Style Specification. @@ -205,13 +205,13 @@ MGL_EXPORT #else /** The geometry's offset. - + This property is measured in points. - + The default value of this property is an `MGLStyleValue` object containing 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. - + This attribute corresponds to the circle-translate layout property in the Mapbox Style Specification. @@ -223,14 +223,14 @@ MGL_EXPORT /** Controls the translation reference point. - + 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. - + This property is only applied to the style if `circleTranslation` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the circle-translate-anchor layout property in the Mapbox Style Specification. diff --git a/platform/darwin/src/MGLCircleStyleLayer.mm b/platform/darwin/src/MGLCircleStyleLayer.mm index 4a639db9950..fc8e3a40c77 100644 --- a/platform/darwin/src/MGLCircleStyleLayer.mm +++ b/platform/darwin/src/MGLCircleStyleLayer.mm @@ -136,57 +136,69 @@ - (void)removeFromMapView:(MGLMapView *)mapView - (void)setCircleBlur:(MGLStyleValue *)circleBlur { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(circleBlur); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(circleBlur); self.rawLayer->setCircleBlur(mbglValue); } - (MGLStyleValue *)circleBlur { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getCircleBlur() ?: self.rawLayer->getDefaultCircleBlur(); - return MGLStyleValueTransformer().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getCircleBlur(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleBlur()); + } + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setCircleColor:(MGLStyleValue *)circleColor { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(circleColor); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(circleColor); self.rawLayer->setCircleColor(mbglValue); } - (MGLStyleValue *)circleColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getCircleColor() ?: self.rawLayer->getDefaultCircleColor(); - return MGLStyleValueTransformer().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getCircleColor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleColor()); + } + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setCircleOpacity:(MGLStyleValue *)circleOpacity { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(circleOpacity); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(circleOpacity); self.rawLayer->setCircleOpacity(mbglValue); } - (MGLStyleValue *)circleOpacity { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getCircleOpacity() ?: self.rawLayer->getDefaultCircleOpacity(); - return MGLStyleValueTransformer().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getCircleOpacity(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleOpacity()); + } + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setCircleRadius:(MGLStyleValue *)circleRadius { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(circleRadius); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(circleRadius); self.rawLayer->setCircleRadius(mbglValue); } - (MGLStyleValue *)circleRadius { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getCircleRadius() ?: self.rawLayer->getDefaultCircleRadius(); - return MGLStyleValueTransformer().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getCircleRadius(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleRadius()); + } + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setCircleScaleAlignment:(MGLStyleValue *)circleScaleAlignment { @@ -199,7 +211,10 @@ - (void)setCircleScaleAlignment:(MGLStyleValue *)circleScaleAlignment - (MGLStyleValue *)circleScaleAlignment { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getCirclePitchScale() ?: self.rawLayer->getDefaultCirclePitchScale(); + auto propertyValue = self.rawLayer->getCirclePitchScale(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultCirclePitchScale()); + } return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); } @@ -213,56 +228,68 @@ - (void)setCirclePitchScale:(MGLStyleValue *)circlePitchScale { - (void)setCircleStrokeColor:(MGLStyleValue *)circleStrokeColor { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(circleStrokeColor); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(circleStrokeColor); self.rawLayer->setCircleStrokeColor(mbglValue); } - (MGLStyleValue *)circleStrokeColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getCircleStrokeColor() ?: self.rawLayer->getDefaultCircleStrokeColor(); - return MGLStyleValueTransformer().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getCircleStrokeColor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleStrokeColor()); + } + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setCircleStrokeOpacity:(MGLStyleValue *)circleStrokeOpacity { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(circleStrokeOpacity); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(circleStrokeOpacity); self.rawLayer->setCircleStrokeOpacity(mbglValue); } - (MGLStyleValue *)circleStrokeOpacity { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getCircleStrokeOpacity() ?: self.rawLayer->getDefaultCircleStrokeOpacity(); - return MGLStyleValueTransformer().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getCircleStrokeOpacity(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleStrokeOpacity()); + } + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setCircleStrokeWidth:(MGLStyleValue *)circleStrokeWidth { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(circleStrokeWidth); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(circleStrokeWidth); self.rawLayer->setCircleStrokeWidth(mbglValue); } - (MGLStyleValue *)circleStrokeWidth { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getCircleStrokeWidth() ?: self.rawLayer->getDefaultCircleStrokeWidth(); - return MGLStyleValueTransformer().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getCircleStrokeWidth(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleStrokeWidth()); + } + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setCircleTranslation:(MGLStyleValue *)circleTranslation { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer, NSValue *>().toPropertyValue(circleTranslation); + auto mbglValue = MGLStyleValueTransformer, NSValue *>().toInterpolatablePropertyValue(circleTranslation); self.rawLayer->setCircleTranslate(mbglValue); } - (MGLStyleValue *)circleTranslation { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getCircleTranslate() ?: self.rawLayer->getDefaultCircleTranslate(); + auto propertyValue = self.rawLayer->getCircleTranslate(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer, NSValue *>().toStyleValue(self.rawLayer->getDefaultCircleTranslate()); + } return MGLStyleValueTransformer, NSValue *>().toStyleValue(propertyValue); } @@ -283,7 +310,10 @@ - (void)setCircleTranslationAnchor:(MGLStyleValue *)circleTranslation - (MGLStyleValue *)circleTranslationAnchor { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getCircleTranslateAnchor() ?: self.rawLayer->getDefaultCircleTranslateAnchor(); + auto propertyValue = self.rawLayer->getCircleTranslateAnchor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultCircleTranslateAnchor()); + } return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); } diff --git a/platform/darwin/src/MGLFillStyleLayer.h b/platform/darwin/src/MGLFillStyleLayer.h index f4ba7a0098f..86f3b1fab0d 100644 --- a/platform/darwin/src/MGLFillStyleLayer.h +++ b/platform/darwin/src/MGLFillStyleLayer.h @@ -27,7 +27,7 @@ typedef NS_ENUM(NSUInteger, MGLFillTranslationAnchor) { /** An `MGLFillStyleLayer` is a style layer that renders one or more filled (and 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 @@ -56,11 +56,11 @@ 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. - + This attribute corresponds to the fill-antialias layout property in the Mapbox Style Specification. @@ -72,11 +72,11 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** The color of the filled part of this layer. - + The default value of this property is an `MGLStyleValue` object containing `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. */ @@ -84,11 +84,11 @@ MGL_EXPORT #else /** The color of the filled part of this layer. - + The default value of this property is an `MGLStyleValue` object containing `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. */ @@ -98,7 +98,7 @@ 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. @@ -108,7 +108,7 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** 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. @@ -117,7 +117,7 @@ MGL_EXPORT #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. @@ -134,13 +134,13 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** The geometry's offset. - + This property is measured in points. - + The default value of this property is an `MGLStyleValue` object containing 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. - + This attribute corresponds to the fill-translate layout property in the Mapbox Style Specification. @@ -149,13 +149,13 @@ MGL_EXPORT #else /** The geometry's offset. - + This property is measured in points. - + The default value of this property is an `MGLStyleValue` object containing 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. - + This attribute corresponds to the fill-translate layout property in the Mapbox Style Specification. @@ -167,14 +167,14 @@ MGL_EXPORT /** Controls the translation reference point. - + 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. - + This property is only applied to the style if `fillTranslation` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the fill-translate-anchor layout property in the Mapbox Style Specification. diff --git a/platform/darwin/src/MGLFillStyleLayer.mm b/platform/darwin/src/MGLFillStyleLayer.mm index 57014e6f601..6212bce410d 100644 --- a/platform/darwin/src/MGLFillStyleLayer.mm +++ b/platform/darwin/src/MGLFillStyleLayer.mm @@ -138,7 +138,10 @@ - (void)setFillAntialiased:(MGLStyleValue *)fillAntialiased { - (MGLStyleValue *)isFillAntialiased { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getFillAntialias() ?: self.rawLayer->getDefaultFillAntialias(); + auto propertyValue = self.rawLayer->getFillAntialias(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultFillAntialias()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -152,43 +155,52 @@ - (void)setFillAntialias:(MGLStyleValue *)fillAntialias { - (void)setFillColor:(MGLStyleValue *)fillColor { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(fillColor); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(fillColor); self.rawLayer->setFillColor(mbglValue); } - (MGLStyleValue *)fillColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getFillColor() ?: self.rawLayer->getDefaultFillColor(); - return MGLStyleValueTransformer().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getFillColor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultFillColor()); + } + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setFillOpacity:(MGLStyleValue *)fillOpacity { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(fillOpacity); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(fillOpacity); self.rawLayer->setFillOpacity(mbglValue); } - (MGLStyleValue *)fillOpacity { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getFillOpacity() ?: self.rawLayer->getDefaultFillOpacity(); - return MGLStyleValueTransformer().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getFillOpacity(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultFillOpacity()); + } + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setFillOutlineColor:(MGLStyleValue *)fillOutlineColor { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(fillOutlineColor); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(fillOutlineColor); self.rawLayer->setFillOutlineColor(mbglValue); } - (MGLStyleValue *)fillOutlineColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getFillOutlineColor() ?: self.rawLayer->getDefaultFillOutlineColor(); - return MGLStyleValueTransformer().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getFillOutlineColor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultFillOutlineColor()); + } + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setFillPattern:(MGLStyleValue *)fillPattern { @@ -201,21 +213,27 @@ - (void)setFillPattern:(MGLStyleValue *)fillPattern { - (MGLStyleValue *)fillPattern { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getFillPattern() ?: self.rawLayer->getDefaultFillPattern(); + auto propertyValue = self.rawLayer->getFillPattern(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultFillPattern()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setFillTranslation:(MGLStyleValue *)fillTranslation { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer, NSValue *>().toPropertyValue(fillTranslation); + auto mbglValue = MGLStyleValueTransformer, NSValue *>().toInterpolatablePropertyValue(fillTranslation); self.rawLayer->setFillTranslate(mbglValue); } - (MGLStyleValue *)fillTranslation { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getFillTranslate() ?: self.rawLayer->getDefaultFillTranslate(); + auto propertyValue = self.rawLayer->getFillTranslate(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer, NSValue *>().toStyleValue(self.rawLayer->getDefaultFillTranslate()); + } return MGLStyleValueTransformer, NSValue *>().toStyleValue(propertyValue); } @@ -236,7 +254,10 @@ - (void)setFillTranslationAnchor:(MGLStyleValue *)fillTranslationAnch - (MGLStyleValue *)fillTranslationAnchor { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getFillTranslateAnchor() ?: self.rawLayer->getDefaultFillTranslateAnchor(); + auto propertyValue = self.rawLayer->getFillTranslateAnchor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultFillTranslateAnchor()); + } return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); } diff --git a/platform/darwin/src/MGLLineStyleLayer.h b/platform/darwin/src/MGLLineStyleLayer.h index d8c8f6a466b..26eb310d8e4 100644 --- a/platform/darwin/src/MGLLineStyleLayer.h +++ b/platform/darwin/src/MGLLineStyleLayer.h @@ -77,7 +77,7 @@ typedef NS_ENUM(NSUInteger, MGLLineTranslationAnchor) { /** An `MGLLineStyleLayer` is a style layer that renders one or more stroked 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 @@ -111,7 +111,7 @@ 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. @@ -120,7 +120,7 @@ MGL_EXPORT /** 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. @@ -129,11 +129,11 @@ MGL_EXPORT /** 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. - + 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. @@ -142,11 +142,11 @@ MGL_EXPORT /** 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. - + 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. @@ -157,9 +157,9 @@ MGL_EXPORT /** Blur applied to the line, in points. - + 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. @@ -169,11 +169,11 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** The color with which the line will be drawn. - + The default value of this property is an `MGLStyleValue` object containing `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. */ @@ -181,11 +181,11 @@ MGL_EXPORT #else /** The color with which the line will be drawn. - + The default value of this property is an `MGLStyleValue` object containing `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. */ @@ -196,12 +196,12 @@ 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. - + This property is measured in line widths. - + This property is only applied to the style if `linePattern` is set to `nil`. Otherwise, it is ignored. - + This attribute corresponds to the line-dasharray layout property in the Mapbox Style Specification. @@ -213,9 +213,9 @@ MGL_EXPORT /** Draws a line casing outside of a line's actual path. Value indicates the width of the inner gap. - + 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. @@ -227,9 +227,9 @@ MGL_EXPORT the right, relative to the direction of the line, and a negative value to the left. For polygon features, a positive value results in an inset, and a negative value results in an outset. - + 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. @@ -238,7 +238,7 @@ 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. @@ -254,13 +254,13 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** The geometry's offset. - + This property is measured in points. - + The default value of this property is an `MGLStyleValue` object containing 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. - + This attribute corresponds to the line-translate layout property in the Mapbox Style Specification. @@ -269,13 +269,13 @@ MGL_EXPORT #else /** The geometry's offset. - + This property is measured in points. - + The default value of this property is an `MGLStyleValue` object containing 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. - + This attribute corresponds to the line-translate layout property in the Mapbox Style Specification. @@ -287,14 +287,14 @@ MGL_EXPORT /** Controls the translation reference point. - + 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. - + This property is only applied to the style if `lineTranslation` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the line-translate-anchor layout property in the Mapbox Style Specification. @@ -305,9 +305,9 @@ MGL_EXPORT /** 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. diff --git a/platform/darwin/src/MGLLineStyleLayer.mm b/platform/darwin/src/MGLLineStyleLayer.mm index 73ffa9a5ae4..6f1d2ee249e 100644 --- a/platform/darwin/src/MGLLineStyleLayer.mm +++ b/platform/darwin/src/MGLLineStyleLayer.mm @@ -150,7 +150,10 @@ - (void)setLineCap:(MGLStyleValue *)lineCap { - (MGLStyleValue *)lineCap { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getLineCap() ?: self.rawLayer->getDefaultLineCap(); + auto propertyValue = self.rawLayer->getLineCap(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultLineCap()); + } return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); } @@ -164,35 +167,44 @@ - (void)setLineJoin:(MGLStyleValue *)lineJoin { - (MGLStyleValue *)lineJoin { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getLineJoin() ?: self.rawLayer->getDefaultLineJoin(); + auto propertyValue = self.rawLayer->getLineJoin(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultLineJoin()); + } return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); } - (void)setLineMiterLimit:(MGLStyleValue *)lineMiterLimit { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(lineMiterLimit); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(lineMiterLimit); self.rawLayer->setLineMiterLimit(mbglValue); } - (MGLStyleValue *)lineMiterLimit { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getLineMiterLimit() ?: self.rawLayer->getDefaultLineMiterLimit(); + auto propertyValue = self.rawLayer->getLineMiterLimit(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultLineMiterLimit()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setLineRoundLimit:(MGLStyleValue *)lineRoundLimit { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(lineRoundLimit); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(lineRoundLimit); self.rawLayer->setLineRoundLimit(mbglValue); } - (MGLStyleValue *)lineRoundLimit { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getLineRoundLimit() ?: self.rawLayer->getDefaultLineRoundLimit(); + auto propertyValue = self.rawLayer->getLineRoundLimit(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultLineRoundLimit()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -201,29 +213,35 @@ - (void)setLineRoundLimit:(MGLStyleValue *)lineRoundLimit { - (void)setLineBlur:(MGLStyleValue *)lineBlur { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(lineBlur); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(lineBlur); self.rawLayer->setLineBlur(mbglValue); } - (MGLStyleValue *)lineBlur { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getLineBlur() ?: self.rawLayer->getDefaultLineBlur(); - return MGLStyleValueTransformer().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getLineBlur(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultLineBlur()); + } + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setLineColor:(MGLStyleValue *)lineColor { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(lineColor); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(lineColor); self.rawLayer->setLineColor(mbglValue); } - (MGLStyleValue *)lineColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getLineColor() ?: self.rawLayer->getDefaultLineColor(); - return MGLStyleValueTransformer().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getLineColor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultLineColor()); + } + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setLineDashPattern:(MGLStyleValue *> *)lineDashPattern { @@ -236,7 +254,10 @@ - (void)setLineDashPattern:(MGLStyleValue *> *)lineDashPatte - (MGLStyleValue *> *)lineDashPattern { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getLineDasharray() ?: self.rawLayer->getDefaultLineDasharray(); + auto propertyValue = self.rawLayer->getLineDasharray(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer, NSArray *, float>().toStyleValue(self.rawLayer->getDefaultLineDasharray()); + } return MGLStyleValueTransformer, NSArray *, float>().toStyleValue(propertyValue); } @@ -250,43 +271,52 @@ - (void)setLineDasharray:(MGLStyleValue *> *)lineDasharray { - (void)setLineGapWidth:(MGLStyleValue *)lineGapWidth { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(lineGapWidth); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(lineGapWidth); self.rawLayer->setLineGapWidth(mbglValue); } - (MGLStyleValue *)lineGapWidth { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getLineGapWidth() ?: self.rawLayer->getDefaultLineGapWidth(); - return MGLStyleValueTransformer().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getLineGapWidth(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultLineGapWidth()); + } + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setLineOffset:(MGLStyleValue *)lineOffset { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(lineOffset); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(lineOffset); self.rawLayer->setLineOffset(mbglValue); } - (MGLStyleValue *)lineOffset { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getLineOffset() ?: self.rawLayer->getDefaultLineOffset(); - return MGLStyleValueTransformer().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getLineOffset(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultLineOffset()); + } + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setLineOpacity:(MGLStyleValue *)lineOpacity { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(lineOpacity); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(lineOpacity); self.rawLayer->setLineOpacity(mbglValue); } - (MGLStyleValue *)lineOpacity { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getLineOpacity() ?: self.rawLayer->getDefaultLineOpacity(); - return MGLStyleValueTransformer().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getLineOpacity(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultLineOpacity()); + } + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setLinePattern:(MGLStyleValue *)linePattern { @@ -299,21 +329,27 @@ - (void)setLinePattern:(MGLStyleValue *)linePattern { - (MGLStyleValue *)linePattern { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getLinePattern() ?: self.rawLayer->getDefaultLinePattern(); + auto propertyValue = self.rawLayer->getLinePattern(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultLinePattern()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setLineTranslation:(MGLStyleValue *)lineTranslation { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer, NSValue *>().toPropertyValue(lineTranslation); + auto mbglValue = MGLStyleValueTransformer, NSValue *>().toInterpolatablePropertyValue(lineTranslation); self.rawLayer->setLineTranslate(mbglValue); } - (MGLStyleValue *)lineTranslation { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getLineTranslate() ?: self.rawLayer->getDefaultLineTranslate(); + auto propertyValue = self.rawLayer->getLineTranslate(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer, NSValue *>().toStyleValue(self.rawLayer->getDefaultLineTranslate()); + } return MGLStyleValueTransformer, NSValue *>().toStyleValue(propertyValue); } @@ -334,7 +370,10 @@ - (void)setLineTranslationAnchor:(MGLStyleValue *)lineTranslationAnch - (MGLStyleValue *)lineTranslationAnchor { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getLineTranslateAnchor() ?: self.rawLayer->getDefaultLineTranslateAnchor(); + auto propertyValue = self.rawLayer->getLineTranslateAnchor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultLineTranslateAnchor()); + } return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); } @@ -348,14 +387,17 @@ - (void)setLineTranslateAnchor:(MGLStyleValue *)lineTranslateAnchor { - (void)setLineWidth:(MGLStyleValue *)lineWidth { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(lineWidth); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(lineWidth); self.rawLayer->setLineWidth(mbglValue); } - (MGLStyleValue *)lineWidth { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getLineWidth() ?: self.rawLayer->getDefaultLineWidth(); + auto propertyValue = self.rawLayer->getLineWidth(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultLineWidth()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } diff --git a/platform/darwin/src/MGLRasterStyleLayer.h b/platform/darwin/src/MGLRasterStyleLayer.h index d2b887d56fd..f10a63b979e 100644 --- a/platform/darwin/src/MGLRasterStyleLayer.h +++ b/platform/darwin/src/MGLRasterStyleLayer.h @@ -9,7 +9,7 @@ NS_ASSUME_NONNULL_BEGIN /** An `MGLRasterStyleLayer` is a style layer that renders raster tiles on the map. - + 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 Mapbox @@ -41,11 +41,11 @@ 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. - + This attribute corresponds to the raster-brightness-max layout property in the Mapbox Style Specification. @@ -57,11 +57,11 @@ MGL_EXPORT /** 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. - + This attribute corresponds to the raster-brightness-min layout property in the Mapbox Style Specification. @@ -72,7 +72,7 @@ MGL_EXPORT /** 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. @@ -81,9 +81,9 @@ MGL_EXPORT /** Fade duration when a new tile is added. - + 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. @@ -92,13 +92,13 @@ MGL_EXPORT /** 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. - + This attribute corresponds to the raster-hue-rotate layout property in the Mapbox Style Specification. @@ -109,7 +109,7 @@ MGL_EXPORT /** 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. @@ -118,7 +118,7 @@ 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. diff --git a/platform/darwin/src/MGLRasterStyleLayer.mm b/platform/darwin/src/MGLRasterStyleLayer.mm index 1e0b1602f58..d633bec4354 100644 --- a/platform/darwin/src/MGLRasterStyleLayer.mm +++ b/platform/darwin/src/MGLRasterStyleLayer.mm @@ -93,14 +93,17 @@ - (void)removeFromMapView:(MGLMapView *)mapView - (void)setMaximumRasterBrightness:(MGLStyleValue *)maximumRasterBrightness { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(maximumRasterBrightness); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(maximumRasterBrightness); self.rawLayer->setRasterBrightnessMax(mbglValue); } - (MGLStyleValue *)maximumRasterBrightness { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getRasterBrightnessMax() ?: self.rawLayer->getDefaultRasterBrightnessMax(); + auto propertyValue = self.rawLayer->getRasterBrightnessMax(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultRasterBrightnessMax()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -114,14 +117,17 @@ - (void)setRasterBrightnessMax:(MGLStyleValue *)rasterBrightnessMax - (void)setMinimumRasterBrightness:(MGLStyleValue *)minimumRasterBrightness { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(minimumRasterBrightness); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(minimumRasterBrightness); self.rawLayer->setRasterBrightnessMin(mbglValue); } - (MGLStyleValue *)minimumRasterBrightness { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getRasterBrightnessMin() ?: self.rawLayer->getDefaultRasterBrightnessMin(); + auto propertyValue = self.rawLayer->getRasterBrightnessMin(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultRasterBrightnessMin()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -135,42 +141,51 @@ - (void)setRasterBrightnessMin:(MGLStyleValue *)rasterBrightnessMin - (void)setRasterContrast:(MGLStyleValue *)rasterContrast { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(rasterContrast); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(rasterContrast); self.rawLayer->setRasterContrast(mbglValue); } - (MGLStyleValue *)rasterContrast { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getRasterContrast() ?: self.rawLayer->getDefaultRasterContrast(); + auto propertyValue = self.rawLayer->getRasterContrast(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultRasterContrast()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setRasterFadeDuration:(MGLStyleValue *)rasterFadeDuration { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(rasterFadeDuration); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(rasterFadeDuration); self.rawLayer->setRasterFadeDuration(mbglValue); } - (MGLStyleValue *)rasterFadeDuration { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getRasterFadeDuration() ?: self.rawLayer->getDefaultRasterFadeDuration(); + auto propertyValue = self.rawLayer->getRasterFadeDuration(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultRasterFadeDuration()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setRasterHueRotation:(MGLStyleValue *)rasterHueRotation { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(rasterHueRotation); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(rasterHueRotation); self.rawLayer->setRasterHueRotate(mbglValue); } - (MGLStyleValue *)rasterHueRotation { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getRasterHueRotate() ?: self.rawLayer->getDefaultRasterHueRotate(); + auto propertyValue = self.rawLayer->getRasterHueRotate(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultRasterHueRotate()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -184,28 +199,34 @@ - (void)setRasterHueRotate:(MGLStyleValue *)rasterHueRotate { - (void)setRasterOpacity:(MGLStyleValue *)rasterOpacity { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(rasterOpacity); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(rasterOpacity); self.rawLayer->setRasterOpacity(mbglValue); } - (MGLStyleValue *)rasterOpacity { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getRasterOpacity() ?: self.rawLayer->getDefaultRasterOpacity(); + auto propertyValue = self.rawLayer->getRasterOpacity(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultRasterOpacity()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setRasterSaturation:(MGLStyleValue *)rasterSaturation { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(rasterSaturation); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(rasterSaturation); self.rawLayer->setRasterSaturation(mbglValue); } - (MGLStyleValue *)rasterSaturation { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getRasterSaturation() ?: self.rawLayer->getDefaultRasterSaturation(); + auto propertyValue = self.rawLayer->getRasterSaturation(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultRasterSaturation()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } diff --git a/platform/darwin/src/MGLStyleLayer.mm.ejs b/platform/darwin/src/MGLStyleLayer.mm.ejs index 42b366905c8..3d9e317c19d 100644 --- a/platform/darwin/src/MGLStyleLayer.mm.ejs +++ b/platform/darwin/src/MGLStyleLayer.mm.ejs @@ -176,24 +176,42 @@ namespace mbgl { - (void)set<%- camelize(property.name) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCName(property) %> { MGLAssertStyleLayerIsValid(); +<% if (property["property-function"]) { -%> + auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toDataDrivenPropertyValue(<%- objCName(property) %>); +<% } else { -%> <% if (property.type == "enum") { -%> auto mbglValue = MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>); - self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue); -<% } else { -%> +<% } else if (property.function == "piecewise-constant") { -%> auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue(<%- objCName(property) %>); - self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue); +<% } else { -%> + auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toInterpolatablePropertyValue(<%- objCName(property) %>); +<% } -%> <% } -%> + self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue); } - (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCGetter(property) %> { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>(); + 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)) %>()); + } 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); <% } -%> +<% } -%> } <% if (property.original) { -%> @@ -214,24 +232,42 @@ namespace mbgl { - (void)set<%- camelize(property.name) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCName(property) %> { MGLAssertStyleLayerIsValid(); +<% if (property["property-function"]) { -%> + auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toDataDrivenPropertyValue(<%- objCName(property) %>); +<% } else { -%> <% if (property.type == "enum") { -%> auto mbglValue = MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>); - self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue); -<% } else { -%> +<% } else if (property.function == "piecewise-constant") { -%> auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue(<%- objCName(property) %>); - self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue); +<% } else { -%> + auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toInterpolatablePropertyValue(<%- objCName(property) %>); +<% } -%> <% } -%> + self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue); } - (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCGetter(property) %> { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>(); + 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)) %>()); + } 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); <% } -%> +<% } -%> } <% if (property.original) { -%> diff --git a/platform/darwin/src/MGLStyleValue.h b/platform/darwin/src/MGLStyleValue.h index 2f462b5a2ee..c8ec08b6a03 100644 --- a/platform/darwin/src/MGLStyleValue.h +++ b/platform/darwin/src/MGLStyleValue.h @@ -2,9 +2,27 @@ #import #import "MGLFoundation.h" +#import "MGLTypes.h" NS_ASSUME_NONNULL_BEGIN +// TODO: API docs +typedef NSString *MGLStyleFunctionOption NS_STRING_ENUM; + +// TODO: API docs +extern MGL_EXPORT const MGLStyleFunctionOption MGLStyleFunctionOptionInterpolationBase; + +// TODO: API docs +extern MGL_EXPORT const MGLStyleFunctionOption MGLStyleFunctionOptionDefaultValue; + +// TODO: API docs +typedef NS_ENUM(NSUInteger, MGLInterpolationMode) { + MGLInterpolationModeExponential = 0, + MGLInterpolationModeInterval, + MGLInterpolationModeCategorical, + 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 @@ -41,6 +59,8 @@ MGL_EXPORT */ + (instancetype)valueWithRawValue:(T)rawValue; +#pragma mark Function values + /** Creates and returns an `MGLStyleFunction` object representing a linear zoom level function with any number of stops. @@ -48,7 +68,7 @@ MGL_EXPORT @param stops A dictionary associating zoom levels with style values. @return An `MGLStyleFunction` object with the given stops. */ -+ (instancetype)valueWithStops:(NSDictionary *> *)stops; ++ (instancetype)valueWithStops:(NSDictionary *> *)stops __attribute__((deprecated("Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]"))); /** Creates and returns an `MGLStyleFunction` object representing a zoom level @@ -58,7 +78,16 @@ MGL_EXPORT @param stops A dictionary associating zoom levels with style values. @return An `MGLStyleFunction` object with the given interpolation base and stops. */ -+ (instancetype)valueWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *> *)stops; ++ (instancetype)valueWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *> *)stops __attribute__((deprecated("Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]"))); + +// TODO: API docs ++ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode cameraStops:(NS_DICTIONARY_OF(id, MGLStyleValue *) *)stops options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options; + +// TODO: API docs ++ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode sourceStops:(nullable NS_DICTIONARY_OF(id, MGLStyleValue *) *)stops attributeName:(NSString *)attributeName options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options; + +// TODO: API docs ++ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode compositeStops:(NS_DICTIONARY_OF(id, NS_DICTIONARY_OF(id, MGLStyleValue *) *) *)stops attributeName:(NSString *)attributeName options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options; @end @@ -106,75 +135,76 @@ MGL_EXPORT @end -/** - An `MGLStyleFunction` 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 `MGLStyleFunction` objects. Use a zoom - level function to create the illusion of depth and control data density. - - The `MGLStyleFunction` class takes a generic parameter `T` that indicates the - Foundation class being wrapped by this class. - */ MGL_EXPORT -@interface MGLStyleFunction : MGLStyleValue +@interface MGLCameraStyleFunction : MGLStyleValue -#pragma mark Creating a Style Function +// TODO: API docs ++ (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NS_DICTIONARY_OF(id, MGLStyleValue *) *)stops options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options; -/** - Creates and returns an `MGLStyleFunction` object representing a linear zoom - level function with any number of stops. +// TODO: API docs +- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NS_DICTIONARY_OF(id, MGLStyleValue *) *)stops options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options NS_DESIGNATED_INITIALIZER; - @param stops A dictionary associating zoom levels with style values. - @return An `MGLStyleFunction` object with the given stops. - */ -+ (instancetype)functionWithStops:(NSDictionary *> *)stops; +// TODO: API docs +@property (nonatomic) MGLInterpolationMode interpolationMode; -/** - Creates and returns an `MGLStyleFunction` object representing a zoom level - function with an exponential interpolation base and any number of stops. +// TODO: API docs +@property (nonatomic, copy) NS_DICTIONARY_OF(id, MGLStyleValue *) *stops; - @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)functionWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *> *)stops; +// TODO: API docs +@property (nonatomic) CGFloat interpolationBase; -#pragma mark Initializing a Style Function +@end -/** - Returns an `MGLStyleFunction` object representing a zoom level function with an - exponential interpolation base and any number of stops. +@compatibility_alias MGLStyleFunction MGLCameraStyleFunction; - @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:(NSDictionary *> *)stops NS_DESIGNATED_INITIALIZER; +MGL_EXPORT +@interface MGLSourceStyleFunction : MGLStyleValue -#pragma mark Accessing the Parameters of a Function +// TODO: API docs ++ (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(nullable NS_DICTIONARY_OF(id, MGLStyleValue *) *)stops attributeName:(NSString *)attributeName options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options; -/** - The exponential interpolation base of the function’s interpolation curve. +// TODO: API docs +- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(nullable NS_DICTIONARY_OF(id, MGLStyleValue *) *)stops attributeName:(NSString *)attributeName options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options NS_DESIGNATED_INITIALIZER; - 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 by zoom level. - 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. - */ +// TODO: API docs +@property (nonatomic) MGLInterpolationMode interpolationMode; + +// TODO: API docs +@property (nonatomic, copy) NSString *attributeName; + +// TODO: API docs +@property (nonatomic, copy, nullable) NS_DICTIONARY_OF(id, MGLStyleValue *) *stops; + +// TODO: API docs +@property (nonatomic, nullable) MGLStyleValue *defaultValue; + +// TODO: API docs @property (nonatomic) CGFloat interpolationBase; -/** - 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) NSDictionary *> *stops; +@end + +MGL_EXPORT +@interface MGLCompositeStyleFunction : MGLStyleValue + +// TODO: API docs ++ (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NS_DICTIONARY_OF(id, NS_DICTIONARY_OF(id, MGLStyleValue *) *) *)stops attributeName:(NSString *)attributeName options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options; + +- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NS_DICTIONARY_OF(id, NS_DICTIONARY_OF(id, MGLStyleValue *) *) *)stops attributeName:(NSString *)attributeName options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options NS_DESIGNATED_INITIALIZER; + +// TODO: API docs +@property (nonatomic) MGLInterpolationMode interpolationMode; + +// TODO: API docs +@property (nonatomic, copy) NSString *attributeName; + +// TODO: API docs +@property (nonatomic, copy) NS_DICTIONARY_OF(id, NS_DICTIONARY_OF(id, MGLStyleValue *) *) *stops; + +// TODO: API docs +@property (nonatomic, nullable) MGLStyleValue *defaultValue; + +// TODO: API docs +@property (nonatomic) CGFloat interpolationBase; @end diff --git a/platform/darwin/src/MGLStyleValue.mm b/platform/darwin/src/MGLStyleValue.mm index 9e771143783..1a8e6edeab9 100644 --- a/platform/darwin/src/MGLStyleValue.mm +++ b/platform/darwin/src/MGLStyleValue.mm @@ -1,5 +1,8 @@ #import "MGLStyleValue_Private.h" +const MGLStyleFunctionOption MGLStyleFunctionOptionInterpolationBase = @"MGLStyleFunctionOptionInterpolationBase"; +const MGLStyleFunctionOption MGLStyleFunctionOptionDefaultValue = @"MGLStyleFunctionOptionDefaultValue"; + @implementation MGLStyleValue + (instancetype)valueWithRawValue:(id)rawValue { @@ -7,11 +10,23 @@ + (instancetype)valueWithRawValue:(id)rawValue { } + (instancetype)valueWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops { - return [MGLStyleFunction functionWithInterpolationBase:interpolationBase stops:stops]; + return [MGLCameraStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential stops:stops options:@{MGLStyleFunctionOptionInterpolationBase: @(interpolationBase)}]; } + (instancetype)valueWithStops:(NSDictionary *)stops { - return [MGLStyleFunction functionWithStops:stops]; + return [MGLCameraStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential stops:stops options:nil]; +} + ++ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode cameraStops:(NSDictionary *)stops options:(NSDictionary *)options { + return [MGLCameraStyleFunction functionWithInterpolationMode:interpolationMode stops:stops options:options]; +} + ++ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode sourceStops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options { + return [MGLSourceStyleFunction functionWithInterpolationMode:interpolationMode stops:stops attributeName:attributeName options:options]; +} + ++ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode compositeStops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options { + return [MGLCompositeStyleFunction functionWithInterpolationMode:interpolationMode stops:stops attributeName:attributeName options:options]; } @end @@ -47,46 +62,203 @@ - (NSUInteger)hash { @end -@implementation MGLStyleFunction +@implementation MGLCameraStyleFunction + +@synthesize interpolationMode = _interpolationMode; + ++ (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops options:(NSDictionary *)options { + return [[self alloc] initWithInterpolationMode:interpolationMode stops:stops options:options]; +} + +- (instancetype)init { + return [self initWithInterpolationMode:MGLInterpolationModeExponential stops:@{} options:nil]; +} + +- (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]) { + _interpolationMode = interpolationMode; + _stops = stops; + _interpolationBase = 1.0; + + if ([options.allKeys containsObject:MGLStyleFunctionOptionInterpolationBase]) { + if ([options[MGLStyleFunctionOptionInterpolationBase] isKindOfClass:[NSNumber class]]) { + NSNumber *value = (NSNumber *)options[MGLStyleFunctionOptionInterpolationBase]; + _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]; +} -+ (instancetype)functionWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops { - return [[self alloc] initWithInterpolationBase:interpolationBase stops:stops]; +- (BOOL)isEqual:(MGLCameraStyleFunction *)other { + return ([other isKindOfClass:[self class]] + && other.interpolationMode == self.interpolationMode + && [other.stops isEqualToDictionary:self.stops] + && other.interpolationBase == self.interpolationBase); } -+ (instancetype)functionWithStops:(NSDictionary *)stops { - return [[self alloc] initWithInterpolationBase:1 stops:stops]; +- (NSUInteger)hash { + return self.interpolationMode + self.stops.hash + self.interpolationBase; +} + +@end + +@implementation MGLSourceStyleFunction + +@synthesize interpolationMode = _interpolationMode; + ++ (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)init { - return [self initWithInterpolationBase:1 stops:@{}]; + return [self initWithInterpolationMode:MGLInterpolationModeExponential stops:nil attributeName:@"" options:nil]; } -- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops { - if (self = [super init]) { - if (!stops.count) - { - [NSException raise:NSInvalidArgumentException format:@"%@ requires at least one stop.", self]; +- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options { + if (self == [super init]) { + _interpolationMode = interpolationMode; + _stops = stops; + _attributeName = attributeName; + _interpolationBase = 1.0; + + 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"]; + } } - _interpolationBase = interpolationBase; + + if ([options.allKeys containsObject:MGLStyleFunctionOptionInterpolationBase]) { + if ([options[MGLStyleFunctionOptionInterpolationBase] isKindOfClass:[NSNumber class]]) { + NSNumber *value = (NSNumber *)options[MGLStyleFunctionOptionInterpolationBase]; + _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:(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 + self.stops.hash + self.attributeName.hash + self.defaultValue.hash + self.interpolationBase; +} + +@end + +@implementation MGLCompositeStyleFunction + +@synthesize interpolationMode = _interpolationMode; + ++ (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)init { + return [self initWithInterpolationMode:MGLInterpolationModeExponential stops:@{} attributeName:@"" options:nil]; +} + +- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options { + if (self == [super init]) { + _interpolationMode = interpolationMode; _stops = stops; + _attributeName = attributeName; + _interpolationBase = 1.0; + + 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]; + _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, interpolationBase = %f; stops = %@>", + return [NSString stringWithFormat:@"<%@: %p, \ + interpolationMode = %lu, \ + stops = %@, \ + attributeName = %@, \ + defaultValue = %@, \ + interpolationBase = %f>", NSStringFromClass([self class]), (void *)self, - self.interpolationBase, - self.stops]; + (unsigned long)self.interpolationMode, + self.stops, + self.attributeName, + self.defaultValue, + self.interpolationBase]; } -- (BOOL)isEqual:(MGLStyleFunction *)other { - return ([other isKindOfClass:[self class]] && other.interpolationBase == self.interpolationBase - && [other.stops isEqualToDictionary:self.stops]); +- (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.interpolationBase + self.stops.hash; + return self.interpolationMode + self.stops.hash + self.attributeName.hash + self.interpolationBase; } @end diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h index 3772a7902a9..85ebc536b64 100644 --- a/platform/darwin/src/MGLStyleValue_Private.h +++ b/platform/darwin/src/MGLStyleValue_Private.h @@ -4,64 +4,249 @@ #import "NSValue+MGLStyleAttributeAdditions.h" #import "MGLTypes.h" + #import +#include + +#include + #if TARGET_OS_IPHONE #import "UIColor+MGLAdditions.h" #else #import "NSColor+MGLAdditions.h" #endif -#include - template class MGLStyleValueTransformer { public: + // Convert an mbgl property value into an mgl style value MGLStyleValue *toStyleValue(const mbgl::style::PropertyValue &mbglValue) { - if (mbglValue.isConstant()) { - return toStyleConstantValue(mbglValue.asConstant()); - } else if (mbglValue.isFunction()) { - return toStyleFunction(mbglValue.asFunction()); - } else { - return nil; - } + PropertyValueEvaluator evaluator; + return mbglValue.evaluate(evaluator); } + // Convert an mbgl data driven property value into an mgl style value + MGLStyleValue *toDataDrivenStyleValue(const mbgl::style::DataDrivenPropertyValue &mbglValue) { + PropertyValueEvaluator evaluator; + return mbglValue.evaluate(evaluator); + } + + // Convert an mbgl property value containing an enum into an mgl style value template ::value>::type, typename MGLEnum = ObjCEnum, class = typename std::enable_if::value>::type> MGLStyleValue *toEnumStyleValue(const mbgl::style::PropertyValue &mbglValue) { - if (mbglValue.isConstant()) { - return toEnumStyleConstantValue<>(mbglValue.asConstant()); - } else if (mbglValue.isFunction()) { - const auto &mbglStops = mbglValue.asFunction().getStops(); - NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.size()]; - for (const auto &mbglStop : mbglStops) { - stops[@(mbglStop.first)] = toEnumStyleConstantValue<>(mbglStop.second); + EnumPropertyValueEvaluator evaluator; + return mbglValue.evaluate(evaluator); + } + + // Convert an mgl style value into a non interpolatable (camera with interval stops) mbgl property value + mbgl::style::PropertyValue toPropertyValue(MGLStyleValue *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 cameraFunctionValueWithinterpolationMode:stops:options:] instead."]; + return {}; + } + + if ([value isKindOfClass:[MGLStyleConstantValue class]]) { + return toMBGLConstantValue((MGLStyleConstantValue *)value); + } else if ([value isKindOfClass:[MGLCameraStyleFunction class]]) { + MGLCameraStyleFunction *cameraStyleFunction = (MGLCameraStyleFunction *)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) { + [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 {}; + } + } + + // Convert an mgl style value into a non interpolatable (camera with exponential or interval stops) mbgl property value + mbgl::style::PropertyValue toInterpolatablePropertyValue(MGLStyleValue *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 cameraFunctionValueWithinterpolationMode:stops:options:] instead."]; + return {}; + } + + if ([value isKindOfClass:[MGLStyleConstantValue class]]) { + return toMBGLConstantValue((MGLStyleConstantValue *)value); + } else if ([value isKindOfClass:[MGLCameraStyleFunction class]]) { + MGLCameraStyleFunction *cameraStyleFunction = (MGLCameraStyleFunction *)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 [MGLStyleFunction functionWithInterpolationBase:mbglValue.asFunction().getBase() stops:stops]; + 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 { - return nil; + return {}; } } - mbgl::style::PropertyValue toPropertyValue(MGLStyleValue *value) { + // Convert an mgl style value into a mbgl data driven property value + mbgl::style::DataDrivenPropertyValue toDataDrivenPropertyValue(MGLStyleValue *value) { if ([value isKindOfClass:[MGLStyleConstantValue class]]) { - MBGLType mbglValue; - getMBGLValue([(MGLStyleConstantValue *)value rawValue], mbglValue); - return mbglValue; - } else if ([value isKindOfClass:[MGLStyleFunction class]]) { - MGLStyleFunction *function = (MGLStyleFunction *)value; - __block std::vector> mbglStops; - [function.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue * _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"); - mbglStops.emplace_back(zoomKey.floatValue, mbglStopValue.asConstant()); - }]; - return mbgl::style::Function({{mbglStops}}, function.interpolationBase); + return toMBGLConstantValue((MGLStyleConstantValue *)value); + } else if ([value isKindOfClass:[MGLCameraStyleFunction class]]) { + MGLCameraStyleFunction *cameraStyleFunction = (MGLCameraStyleFunction *)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."]; + return {}; + } + } else if ([value isKindOfClass:[MGLSourceStyleFunction class]]) { + MGLSourceStyleFunction *sourceStyleFunction = (MGLSourceStyleFunction *)value; + switch (sourceStyleFunction.interpolationMode) { + case MGLInterpolationModeExponential: + return toMBGLExponentialSourceFunction(sourceStyleFunction); + break; + case MGLInterpolationModeInterval: + return toMBGLIntervalSourceFunction(sourceStyleFunction); + break; + case MGLInterpolationModeCategorical: + return toMBGLCategoricalSourceFunction(sourceStyleFunction); + break; + case MGLInterpolationModeIdentity: + return toMBGLIdentitySourceFunction(sourceStyleFunction); + break; + default: + [NSException raise:NSInvalidArgumentException + format:@"A camera function must use exponential, interval, categorical, or identity stops."]; + return {}; + } + } else if ([value isKindOfClass:[MGLCompositeStyleFunction class]]) { + MGLCompositeStyleFunction *compositeStyleFunction = (MGLCompositeStyleFunction *)value; + switch (compositeStyleFunction.interpolationMode) { + case MGLInterpolationModeExponential: { + __block std::map> outerStops = {}; + [compositeStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, NSDictionary * _Nonnull stopValue, BOOL * _Nonnull stop) { + std::map stops = {}; + for (NSNumber *key in stopValue.allKeys) { + NSCAssert([key isKindOfClass:[NSNumber class]], @"Stop keys should be NSNumbers"); + MGLStyleValue *value = stopValue[key]; + NSCAssert([value isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues"); + auto mbglStopValue = toPropertyValue(value); + NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant"); + stops[key.floatValue] = mbglStopValue.asConstant(); + } + mbgl::style::ExponentialStops innerStops = {stops, (float)compositeStyleFunction.interpolationBase}; + outerStops[zoomKey.floatValue] = innerStops; + }]; + mbgl::style::CompositeFunction compositeFunction = {compositeStyleFunction.attributeName.UTF8String, outerStops}; + if (compositeStyleFunction.defaultValue) { + NSCAssert([compositeStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant"); + MBGLType mbglValue; + id mglValue = [(MGLStyleConstantValue *)compositeStyleFunction.defaultValue rawValue]; + getMBGLValue(mglValue, mbglValue); + compositeFunction.defaultValue = mbglValue; + } + return compositeFunction; + } + break; + case MGLInterpolationModeInterval: { + __block std::map> outerStops = {}; + [compositeStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, NSDictionary * _Nonnull stopValue, BOOL * _Nonnull stop) { + std::map stops = {}; + for (NSNumber *key in stopValue.allKeys) { + NSCAssert([key isKindOfClass:[NSNumber class]], @"Stop keys should be NSNumbers"); + MGLStyleValue *value = stopValue[key]; + NSCAssert([value isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues"); + auto mbglStopValue = toPropertyValue(value); + NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant"); + stops[key.floatValue] = mbglStopValue.asConstant(); + } + mbgl::style::IntervalStops innerStops = {stops}; + outerStops[zoomKey.floatValue] = innerStops; + }]; + mbgl::style::CompositeFunction compositeFunction = {compositeStyleFunction.attributeName.UTF8String, outerStops}; + if (compositeStyleFunction.defaultValue) { + NSCAssert([compositeStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant"); + MBGLType mbglValue; + id mglValue = [(MGLStyleConstantValue *)compositeStyleFunction.defaultValue rawValue]; + getMBGLValue(mglValue, mbglValue); + compositeFunction.defaultValue = mbglValue; + } + return compositeFunction; + } + break; + case MGLInterpolationModeCategorical: { + __block std::map> outerStops = {}; + [compositeStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, NSDictionary * _Nonnull stopValue, BOOL * _Nonnull stop) { + __block std::map stops = {}; + [stopValue enumerateKeysAndObjectsUsingBlock:^(id _Nonnull categoryKey, MGLStyleValue * _Nonnull innerValue, BOOL * _Nonnull stop) { + NSCAssert([innerValue isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues"); + auto mbglStopValue = toPropertyValue(innerValue); + 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 categoricalStops = {stops}; + outerStops[zoomKey.floatValue] = categoricalStops; + }]; + mbgl::style::CompositeFunction compositeFunction = {compositeStyleFunction.attributeName.UTF8String, outerStops}; + if (compositeStyleFunction.defaultValue) { + NSCAssert([compositeStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant"); + MBGLType mbglValue; + id mglValue = [(MGLStyleConstantValue *)compositeStyleFunction.defaultValue rawValue]; + getMBGLValue(mglValue, mbglValue); + compositeFunction.defaultValue = mbglValue; + } + return compositeFunction; + } + break; + default: + [NSException raise:NSInvalidArgumentException + format:@"A composite function must use exponential, interval, or categorical stops."]; + return {}; + } + return {}; } else if (value) { [NSException raise:@"MGLAbstractClassException" format: @"The style value %@ cannot be applied to the style. " @@ -73,25 +258,37 @@ class MGLStyleValueTransformer { } } + // Convert an mgl style value containing an enum into a mbgl property value containing an enum template ::value>::type, typename MGLEnum = ObjCEnum, class = typename std::enable_if::value>::type> mbgl::style::PropertyValue toEnumPropertyValue(MGLStyleValue *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 cameraFunctionValueWithinterpolationMode:stops:options:] instead."]; + return {}; + } + if ([value isKindOfClass:[MGLStyleConstantValue class]]) { MBGLEnum mbglValue; getMBGLValue([(MGLStyleConstantValue *)value rawValue], mbglValue); return mbglValue; - } else if ([value isKindOfClass:[MGLStyleFunction class]]) { - MGLStyleFunction *function = (MGLStyleFunction *)value; - __block std::vector> mbglStops; - [function.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue * _Nonnull stopValue, BOOL * _Nonnull stop) { + } else if ([value isKindOfClass:[MGLCameraStyleFunction class]]) { + MGLCameraStyleFunction *cameraStyleFunction = (MGLCameraStyleFunction *)value; + __block std::map stops = {}; + [cameraStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue * _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"); - mbglStops.emplace_back(zoomKey.floatValue, mbglStopValue.asConstant()); + stops[zoomKey.floatValue] = mbglStopValue.asConstant(); }]; - return mbgl::style::Function({{mbglStops}}, function.interpolationBase); + + // Enumerations can only ever use interval stops. + mbgl::style::IntervalStops intervalStops = {stops}; + + mbgl::style::CameraFunction cameraFunction = {intervalStops}; + return cameraFunction; } else if (value) { [NSException raise:@"MGLAbstractClassException" format: @"The style value %@ cannot be applied to the style. " @@ -103,77 +300,140 @@ class MGLStyleValueTransformer { } } -private: +private: // Private utilities for converting from mgl to mbgl values - MGLStyleConstantValue *toStyleConstantValue(const MBGLType mbglValue) { - auto rawValue = toMGLRawStyleValue(mbglValue); - return [MGLStyleConstantValue valueWithRawValue:rawValue]; + MBGLType toMBGLConstantValue(MGLStyleConstantValue *value) { + MBGLType mbglValue; + getMBGLValue(value.rawValue, mbglValue); + return mbglValue; } - MGLStyleFunction *toStyleFunction(const mbgl::style::Function &mbglFunction) { - const auto &mbglStops = mbglFunction.getStops(); - NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.size()]; - for (const auto &mbglStop : mbglStops) { - auto rawValue = toMGLRawStyleValue(mbglStop.second); - stops[@(mbglStop.first)] = [MGLStyleValue valueWithRawValue:rawValue]; - } - return [MGLStyleFunction functionWithInterpolationBase:mbglFunction.getBase() stops:stops]; - } + mbgl::style::CameraFunction toMBGLExponentialCameraFunction(MGLCameraStyleFunction *cameraStyleFunction) { + __block std::map stops = {}; + [cameraStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue * _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(); + }]; - template ::value>::type, - typename MGLEnum = ObjCEnum, - class = typename std::enable_if::value>::type> - MGLStyleConstantValue *toEnumStyleConstantValue(const MBGLEnum mbglValue) { - auto str = mbgl::Enum::toString(mbglValue); - MGLEnum mglType = *mbgl::Enum::toEnum(str); - return [MGLStyleConstantValue valueWithRawValue:[NSValue value:&mglType withObjCType:@encode(MGLEnum)]]; - } + // Camera function with Exponential stops + mbgl::style::ExponentialStops exponentialStops = {stops, (float)cameraStyleFunction.interpolationBase}; + mbgl::style::CameraFunction cameraFunction = {exponentialStops}; - NSNumber *toMGLRawStyleValue(const bool mbglStopValue) { - return @(mbglStopValue); + return cameraFunction; } - NSNumber *toMGLRawStyleValue(const float mbglStopValue) { - return @(mbglStopValue); - } + mbgl::style::CameraFunction toMBGLIntervalCameraFunction(MGLCameraStyleFunction *cameraStyleFunction) { + __block std::map stops = {}; + [cameraStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue * _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(); + }]; - NSString *toMGLRawStyleValue(const std::string &mbglStopValue) { - return @(mbglStopValue.c_str()); - } + // Camera function with Interval stops + mbgl::style::IntervalStops intervalStops = {stops}; + mbgl::style::CameraFunction cameraFunction = {intervalStops}; - // Offsets - NSValue *toMGLRawStyleValue(const std::array &mbglStopValue) { - return [NSValue mgl_valueWithOffsetArray:mbglStopValue]; + return cameraFunction; } - // Padding - NSValue *toMGLRawStyleValue(const std::array &mbglStopValue) { - return [NSValue mgl_valueWithPaddingArray:mbglStopValue]; + mbgl::style::SourceFunction toMBGLCategoricalSourceFunction(MGLSourceStyleFunction *sourceStyleFunction) { + __block std::map stops = {}; + [sourceStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(id categoryKey, MGLStyleValue *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 categoricalStops = {stops}; + mbgl::style::SourceFunction sourceFunction = {sourceStyleFunction.attributeName.UTF8String, categoricalStops}; + if (sourceStyleFunction.defaultValue) { + NSCAssert([sourceStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant"); + MBGLType mbglValue; + id mglValue = [(MGLStyleConstantValue *)sourceStyleFunction.defaultValue rawValue]; + getMBGLValue(mglValue, mbglValue); + sourceFunction.defaultValue = mbglValue; + } + return sourceFunction; } - MGLColor *toMGLRawStyleValue(const mbgl::Color mbglStopValue) { - return [MGLColor mgl_colorWithColor:mbglStopValue]; + mbgl::style::SourceFunction toMBGLExponentialSourceFunction(MGLSourceStyleFunction *sourceStyleFunction) { + __block std::map stops = {}; + [sourceStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue * _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(); + }]; + mbgl::style::ExponentialStops exponentialStops = {stops, (float)sourceStyleFunction.interpolationBase}; + mbgl::style::SourceFunction sourceFunction = {sourceStyleFunction.attributeName.UTF8String, exponentialStops}; + if (sourceStyleFunction.defaultValue) { + NSCAssert([sourceStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant"); + MBGLType mbglValue; + id mglValue = [(MGLStyleConstantValue *)sourceStyleFunction.defaultValue rawValue]; + getMBGLValue(mglValue, mbglValue); + sourceFunction.defaultValue = mbglValue; + } + return sourceFunction; } - ObjCType toMGLRawStyleValue(const std::vector &mbglStopValue) { - NSMutableArray *array = [NSMutableArray arrayWithCapacity:mbglStopValue.size()]; - for (const auto &mbglElement: mbglStopValue) { - [array addObject:toMGLRawStyleValue(mbglElement)]; + mbgl::style::SourceFunction toMBGLIntervalSourceFunction(MGLSourceStyleFunction *sourceStyleFunction) { + __block std::map stops = {}; + [sourceStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue * _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(); + }]; + mbgl::style::IntervalStops intervalStops = {stops}; + mbgl::style::SourceFunction sourceFunction = {sourceStyleFunction.attributeName.UTF8String, intervalStops}; + if (sourceStyleFunction.defaultValue) { + NSCAssert([sourceStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant"); + MBGLType mbglValue; + id mglValue = [(MGLStyleConstantValue *)sourceStyleFunction.defaultValue rawValue]; + getMBGLValue(mglValue, mbglValue); + sourceFunction.defaultValue = mbglValue; } - return array; + return sourceFunction; } -private: + mbgl::style::SourceFunction toMBGLIdentitySourceFunction(MGLSourceStyleFunction *sourceStyleFunction) { + mbgl::style::IdentityStops identityStops; + mbgl::style::SourceFunction sourceFunction = {sourceStyleFunction.attributeName.UTF8String, identityStops}; + return sourceFunction; + } + // Bool void getMBGLValue(NSNumber *rawValue, bool &mbglValue) { mbglValue = !!rawValue.boolValue; } + // Float void getMBGLValue(NSNumber *rawValue, float &mbglValue) { mbglValue = rawValue.floatValue; } + // String void getMBGLValue(NSString *rawValue, std::string &mbglValue) { mbglValue = rawValue.UTF8String; } @@ -188,10 +448,12 @@ class MGLStyleValueTransformer { mbglValue = rawValue.mgl_paddingArrayValue; } + // Color void getMBGLValue(MGLColor *rawValue, mbgl::Color &mbglValue) { mbglValue = rawValue.mgl_color; } + // Array void getMBGLValue(ObjCType rawValue, std::vector &mbglValue) { mbglValue.reserve(rawValue.count); for (id obj in rawValue) { @@ -212,4 +474,265 @@ class MGLStyleValueTransformer { auto str = mbgl::Enum::toString(mglEnum); mbglValue = *mbgl::Enum::toEnum(str); } + +private: // Private utilities for converting from mbgl to mgl values + + // Bool + static NSNumber *toMGLRawStyleValue(const bool mbglStopValue) { + return @(mbglStopValue); + } + + // Float + static NSNumber *toMGLRawStyleValue(const float mbglStopValue) { + return @(mbglStopValue); + } + + // Integer + static NSNumber *toMGLRawStyleValue(const int64_t mbglStopValue) { + return @(mbglStopValue); + } + + // String + static NSString *toMGLRawStyleValue(const std::string &mbglStopValue) { + return @(mbglStopValue.c_str()); + } + + // Offsets + static NSValue *toMGLRawStyleValue(const std::array &mbglStopValue) { + return [NSValue mgl_valueWithOffsetArray:mbglStopValue]; + } + + // Padding + static NSValue *toMGLRawStyleValue(const std::array &mbglStopValue) { + return [NSValue mgl_valueWithPaddingArray:mbglStopValue]; + } + + // Color + static MGLColor *toMGLRawStyleValue(const mbgl::Color mbglStopValue) { + return [MGLColor mgl_colorWithColor:mbglStopValue]; + } + + // Array + static ObjCType toMGLRawStyleValue(const std::vector &mbglStopValue) { + NSMutableArray *array = [NSMutableArray arrayWithCapacity:mbglStopValue.size()]; + for (const auto &mbglElement: mbglStopValue) { + [array addObject:toMGLRawStyleValue(mbglElement)]; + } + return array; + } + + // Enumerations + template + static NSValue *toMGLRawStyleValue(const MBGLEnum &value) { + auto str = mbgl::Enum::toString(value); + MGLEnum mglType = *mbgl::Enum::toEnum(str); + return [NSValue value:&mglType withObjCType:@encode(MGLEnum)]; + } + + // Converts mbgl stops to an equivilent NSDictionary for mgl + static NSMutableDictionary *toConvertedStops(const std::map &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 + class EnumPropertyValueEvaluator { + public: + id operator()(const mbgl::style::Undefined) const { + return nil; + } + + id operator()(const MBGLEnum &value) const { + auto str = mbgl::Enum::toString(value); + MGLEnum mglType = *mbgl::Enum::toEnum(str); + return [MGLStyleConstantValue valueWithRawValue:[NSValue value:&mglType withObjCType:@encode(MGLEnum)]]; + } + + id operator()(const mbgl::style::CameraFunction &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 &mbglStops) { + return [MGLCameraStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential + stops:toConvertedStops(mbglStops.stops) + options:@{MGLStyleFunctionOptionInterpolationBase: @(mbglStops.base)}]; + } + + id operator()(const mbgl::style::IntervalStops &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 &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 &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 &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 &mbglStops) { + return [MGLSourceStyleFunction functionWithInterpolationMode:MGLInterpolationModeIdentity + stops:nil + attributeName:@(mbglFunction.property.c_str()) options:nil]; + } + + const mbgl::style::SourceFunction &mbglFunction; + }; + + // Converts a composite function and all possible mbgl stops into an equivilant mgl style value + class CompositeFunctionStopsVisitor { + public: + id operator()(const std::map> &mbglStops) { + float base = 1.0f; + NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.size()]; + for (auto const& outerStop: mbglStops) { + stops[@(outerStop.first)] = toConvertedStops(outerStop.second.stops); + base = outerStop.second.base; + } + MGLCompositeStyleFunction *compositeFunction = [MGLCompositeStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential + stops:stops + attributeName:@(mbglFunction.property.c_str()) + options:@{MGLStyleFunctionOptionInterpolationBase: @(base)}]; + if (mbglFunction.defaultValue) { + compositeFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)]; + } + return compositeFunction; + } + + id operator()(const std::map> &mbglStops) { + NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.size()]; + for (auto const& outerStop: mbglStops) { + stops[@(outerStop.first)] = toConvertedStops(outerStop.second.stops); + } + 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 std::map> &mbglStops) { + NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.size()]; + for (auto const& outerStop: mbglStops) { + NSMutableDictionary *innerStops = [NSMutableDictionary dictionaryWithCapacity:outerStop.second.stops.size()]; + for (const auto &mbglStop : outerStop.second.stops) { + 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)]; + } + return compositeFunction; + } + + const mbgl::style::CompositeFunction &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 [MGLStyleConstantValue valueWithRawValue:rawValue]; + } + + id operator()(const mbgl::style::CameraFunction &mbglValue) const { + CameraFunctionStopsVisitor visitor; + return apply_visitor(visitor, mbglValue.stops); + } + + id operator()(const mbgl::style::SourceFunction &mbglValue) const { + SourceFunctionStopsVisitor visitor { mbglValue }; + return apply_visitor(visitor, mbglValue.stops); + } + + MGLCompositeStyleFunction * operator()(const mbgl::style::CompositeFunction &mbglValue) const { + CompositeFunctionStopsVisitor visitor { mbglValue }; + return apply_visitor(visitor, mbglValue.stops); + } + }; }; diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h index 431c87a486d..9739b2fe5cf 100644 --- a/platform/darwin/src/MGLSymbolStyleLayer.h +++ b/platform/darwin/src/MGLSymbolStyleLayer.h @@ -251,7 +251,7 @@ 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. @@ -285,14 +285,14 @@ 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. - + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the icon-allow-overlap layout property in the Mapbox Style Specification. @@ -304,14 +304,14 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the icon-ignore-placement layout property in the Mapbox Style Specification. @@ -323,7 +323,7 @@ MGL_EXPORT /** A string with {tokens} replaced, referencing the data property to pull from. - + This attribute corresponds to the icon-image layout property in the Mapbox Style Specification. @@ -336,11 +336,11 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** Offset distance of icon from its anchor. - + The default value of this property is an `MGLStyleValue` object containing 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. */ @@ -348,11 +348,11 @@ MGL_EXPORT #else /** Offset distance of icon from its anchor. - + The default value of this property is an `MGLStyleValue` object containing 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. */ @@ -362,11 +362,11 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `iconImageName` is non-`nil`, and `text` is non-`nil`. Otherwise, it is ignored. */ @@ -375,13 +375,13 @@ MGL_EXPORT /** Size of the additional area around the icon bounding box used for detecting symbol collisions. - + 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. - + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @@ -389,16 +389,16 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the icon-rotate layout property in the Mapbox Style Specification. @@ -411,11 +411,11 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @@ -423,14 +423,14 @@ MGL_EXPORT /** Scale factor for icon. 1 is original size, 3 triples the size. - + 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. - + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the icon-size layout property in the Mapbox Style Specification. @@ -442,11 +442,11 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `iconImageName` is non-`nil`, and `text` is non-`nil`. Otherwise, it is ignored. */ @@ -455,13 +455,13 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** 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 `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`, @@ -471,13 +471,13 @@ MGL_EXPORT #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 `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`, @@ -488,17 +488,17 @@ MGL_EXPORT /** 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. - + 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. - + This attribute corresponds to the icon-keep-upright layout property in the Mapbox Style Specification. @@ -511,17 +511,17 @@ MGL_EXPORT /** 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. - + 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. - + This attribute corresponds to the text-keep-upright layout property in the Mapbox Style Specification. @@ -533,17 +533,17 @@ MGL_EXPORT /** 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. - + 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. - + This attribute corresponds to the text-max-angle layout property in the Mapbox Style Specification. @@ -555,16 +555,16 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the text-max-width layout property in the Mapbox Style Specification. @@ -579,11 +579,11 @@ MGL_EXPORT Recommended in layers that don't have enough padding in the vector tile to 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. - + This attribute corresponds to the symbol-avoid-edges layout property in the Mapbox Style Specification. @@ -595,7 +595,7 @@ MGL_EXPORT /** 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. @@ -604,13 +604,13 @@ MGL_EXPORT /** 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. - + 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. @@ -620,10 +620,10 @@ MGL_EXPORT /** Value to use for a text label. Feature properties are specified using tokens like {field_name}. - + 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. - + This attribute corresponds to the text-field layout property in the Mapbox Style Specification. @@ -636,14 +636,14 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the text-allow-overlap layout property in the Mapbox Style Specification. @@ -655,11 +655,11 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. */ @@ -667,24 +667,24 @@ MGL_EXPORT /** An array of font face names used to display the text. - + Each font name must be included in the `{fontstack}` portion of the JSON stylesheet’s glyphs property. You can register a custom font when designing the style in Mapbox Studio. Fonts installed on the system are not used. - + The 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. - + 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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the text-font layout property in the Mapbox Style Specification. @@ -696,16 +696,16 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the text-size layout property in the Mapbox Style Specification. @@ -717,14 +717,14 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the text-ignore-placement layout property in the Mapbox Style Specification. @@ -736,14 +736,14 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the text-justify layout property in the Mapbox Style Specification. @@ -755,13 +755,13 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. */ @@ -769,13 +769,13 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. */ @@ -784,13 +784,13 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** 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 `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. */ @@ -798,13 +798,13 @@ MGL_EXPORT #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 `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. */ @@ -814,11 +814,11 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `text` is non-`nil`, and `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @@ -827,13 +827,13 @@ MGL_EXPORT /** Size of the additional area around the text bounding box used for detecting symbol collisions. - + 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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. */ @@ -841,11 +841,11 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. */ @@ -853,16 +853,16 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the text-rotate layout property in the Mapbox Style Specification. @@ -875,11 +875,11 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. */ @@ -887,11 +887,11 @@ MGL_EXPORT /** 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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. */ @@ -903,11 +903,11 @@ 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 `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. */ @@ -916,11 +916,11 @@ 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 `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. */ @@ -929,13 +929,13 @@ MGL_EXPORT /** Fade out the halo towards the outside. - + 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. - + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @@ -945,11 +945,11 @@ 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 `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. */ @@ -958,11 +958,11 @@ 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 `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. */ @@ -971,13 +971,13 @@ MGL_EXPORT /** Distance of halo to the icon outline. - + 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. - + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @@ -985,11 +985,11 @@ 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. - + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @@ -998,16 +998,16 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** 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 `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. - + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the icon-translate layout property in the Mapbox Style Specification. @@ -1016,16 +1016,16 @@ MGL_EXPORT #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 `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. - + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the icon-translate layout property in the Mapbox Style Specification. @@ -1037,14 +1037,14 @@ MGL_EXPORT /** Controls the translation reference point. - + 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. - + This property is only applied to the style if `iconImageName` is non-`nil`, and `iconTranslation` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the icon-translate-anchor layout property in the Mapbox Style Specification. @@ -1056,11 +1056,11 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** The color with which the text will be drawn. - + The default value of this property is an `MGLStyleValue` object containing `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. */ @@ -1068,11 +1068,11 @@ MGL_EXPORT #else /** The color with which the text will be drawn. - + The default value of this property is an `MGLStyleValue` object containing `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. */ @@ -1081,13 +1081,13 @@ MGL_EXPORT /** The halo's fadeout distance towards the outside. - + 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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. */ @@ -1096,11 +1096,11 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** 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 `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. */ @@ -1108,11 +1108,11 @@ MGL_EXPORT #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 `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. */ @@ -1122,13 +1122,13 @@ MGL_EXPORT /** Distance of halo to the font outline. Max text halo width is 1/4 of the 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 `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. */ @@ -1136,11 +1136,11 @@ 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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. */ @@ -1149,16 +1149,16 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** 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 `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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the text-translate layout property in the Mapbox Style Specification. @@ -1167,16 +1167,16 @@ MGL_EXPORT #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 `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. - + This property is only applied to the style if `text` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the text-translate layout property in the Mapbox Style Specification. @@ -1188,14 +1188,14 @@ MGL_EXPORT /** Controls the translation reference point. - + 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. - + This property is only applied to the style if `text` is non-`nil`, and `textTranslation` is non-`nil`. Otherwise, it is ignored. - + This attribute corresponds to the text-translate-anchor layout property in the Mapbox Style Specification. diff --git a/platform/darwin/src/MGLSymbolStyleLayer.mm b/platform/darwin/src/MGLSymbolStyleLayer.mm index b0786d95c2e..8f150e38d45 100644 --- a/platform/darwin/src/MGLSymbolStyleLayer.mm +++ b/platform/darwin/src/MGLSymbolStyleLayer.mm @@ -197,7 +197,10 @@ - (void)setIconAllowsOverlap:(MGLStyleValue *)iconAllowsOverlap { - (MGLStyleValue *)iconAllowsOverlap { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconAllowOverlap() ?: self.rawLayer->getDefaultIconAllowOverlap(); + auto propertyValue = self.rawLayer->getIconAllowOverlap(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultIconAllowOverlap()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -218,7 +221,10 @@ - (void)setIconIgnoresPlacement:(MGLStyleValue *)iconIgnoresPlacemen - (MGLStyleValue *)iconIgnoresPlacement { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconIgnorePlacement() ?: self.rawLayer->getDefaultIconIgnorePlacement(); + auto propertyValue = self.rawLayer->getIconIgnorePlacement(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultIconIgnorePlacement()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -239,7 +245,10 @@ - (void)setIconImageName:(MGLStyleValue *)iconImageName { - (MGLStyleValue *)iconImageName { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconImage() ?: self.rawLayer->getDefaultIconImage(); + auto propertyValue = self.rawLayer->getIconImage(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultIconImage()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -253,15 +262,18 @@ - (void)setIconImage:(MGLStyleValue *)iconImage { - (void)setIconOffset:(MGLStyleValue *)iconOffset { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer, NSValue *>().toPropertyValue(iconOffset); + auto mbglValue = MGLStyleValueTransformer, NSValue *>().toDataDrivenPropertyValue(iconOffset); self.rawLayer->setIconOffset(mbglValue); } - (MGLStyleValue *)iconOffset { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconOffset() ?: self.rawLayer->getDefaultIconOffset(); - return MGLStyleValueTransformer, NSValue *>().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getIconOffset(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer, NSValue *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconOffset()); + } + return MGLStyleValueTransformer, NSValue *>().toDataDrivenStyleValue(propertyValue); } - (void)setIconOptional:(MGLStyleValue *)iconOptional { @@ -274,36 +286,45 @@ - (void)setIconOptional:(MGLStyleValue *)iconOptional { - (MGLStyleValue *)isIconOptional { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconOptional() ?: self.rawLayer->getDefaultIconOptional(); + auto propertyValue = self.rawLayer->getIconOptional(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultIconOptional()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setIconPadding:(MGLStyleValue *)iconPadding { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(iconPadding); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(iconPadding); self.rawLayer->setIconPadding(mbglValue); } - (MGLStyleValue *)iconPadding { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconPadding() ?: self.rawLayer->getDefaultIconPadding(); + auto propertyValue = self.rawLayer->getIconPadding(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultIconPadding()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setIconRotation:(MGLStyleValue *)iconRotation { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(iconRotation); + auto mbglValue = MGLStyleValueTransformer().toDataDrivenPropertyValue(iconRotation); self.rawLayer->setIconRotate(mbglValue); } - (MGLStyleValue *)iconRotation { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconRotate() ?: self.rawLayer->getDefaultIconRotate(); - return MGLStyleValueTransformer().toStyleValue(propertyValue); + auto propertyValue = self.rawLayer->getIconRotate(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toDataDrivenStyleValue(self.rawLayer->getDefaultIconRotate()); + } + return MGLStyleValueTransformer().toDataDrivenStyleValue(propertyValue); } - (void)setIconRotate:(MGLStyleValue *)iconRotate { @@ -323,21 +344,27 @@ - (void)setIconRotationAlignment:(MGLStyleValue *)iconRotationAlignme - (MGLStyleValue *)iconRotationAlignment { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconRotationAlignment() ?: self.rawLayer->getDefaultIconRotationAlignment(); + auto propertyValue = self.rawLayer->getIconRotationAlignment(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultIconRotationAlignment()); + } return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); } - (void)setIconScale:(MGLStyleValue *)iconScale { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(iconScale); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(iconScale); self.rawLayer->setIconSize(mbglValue); } - (MGLStyleValue *)iconScale { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconSize() ?: self.rawLayer->getDefaultIconSize(); + auto propertyValue = self.rawLayer->getIconSize(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultIconSize()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -358,21 +385,27 @@ - (void)setIconTextFit:(MGLStyleValue *)iconTextFit { - (MGLStyleValue *)iconTextFit { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconTextFit() ?: self.rawLayer->getDefaultIconTextFit(); + auto propertyValue = self.rawLayer->getIconTextFit(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultIconTextFit()); + } return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); } - (void)setIconTextFitPadding:(MGLStyleValue *)iconTextFitPadding { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer, NSValue *>().toPropertyValue(iconTextFitPadding); + auto mbglValue = MGLStyleValueTransformer, NSValue *>().toInterpolatablePropertyValue(iconTextFitPadding); self.rawLayer->setIconTextFitPadding(mbglValue); } - (MGLStyleValue *)iconTextFitPadding { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconTextFitPadding() ?: self.rawLayer->getDefaultIconTextFitPadding(); + auto propertyValue = self.rawLayer->getIconTextFitPadding(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer, NSValue *>().toStyleValue(self.rawLayer->getDefaultIconTextFitPadding()); + } return MGLStyleValueTransformer, NSValue *>().toStyleValue(propertyValue); } @@ -386,7 +419,10 @@ - (void)setKeepsIconUpright:(MGLStyleValue *)keepsIconUpright { - (MGLStyleValue *)keepsIconUpright { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconKeepUpright() ?: self.rawLayer->getDefaultIconKeepUpright(); + auto propertyValue = self.rawLayer->getIconKeepUpright(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultIconKeepUpright()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -407,7 +443,10 @@ - (void)setKeepsTextUpright:(MGLStyleValue *)keepsTextUpright { - (MGLStyleValue *)keepsTextUpright { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextKeepUpright() ?: self.rawLayer->getDefaultTextKeepUpright(); + auto propertyValue = self.rawLayer->getTextKeepUpright(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextKeepUpright()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -421,14 +460,17 @@ - (void)setTextKeepUpright:(MGLStyleValue *)textKeepUpright { - (void)setMaximumTextAngle:(MGLStyleValue *)maximumTextAngle { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(maximumTextAngle); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(maximumTextAngle); self.rawLayer->setTextMaxAngle(mbglValue); } - (MGLStyleValue *)maximumTextAngle { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextMaxAngle() ?: self.rawLayer->getDefaultTextMaxAngle(); + auto propertyValue = self.rawLayer->getTextMaxAngle(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextMaxAngle()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -442,14 +484,17 @@ - (void)setTextMaxAngle:(MGLStyleValue *)textMaxAngle { - (void)setMaximumTextWidth:(MGLStyleValue *)maximumTextWidth { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(maximumTextWidth); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(maximumTextWidth); self.rawLayer->setTextMaxWidth(mbglValue); } - (MGLStyleValue *)maximumTextWidth { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextMaxWidth() ?: self.rawLayer->getDefaultTextMaxWidth(); + auto propertyValue = self.rawLayer->getTextMaxWidth(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextMaxWidth()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -470,7 +515,10 @@ - (void)setSymbolAvoidsEdges:(MGLStyleValue *)symbolAvoidsEdges { - (MGLStyleValue *)symbolAvoidsEdges { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getSymbolAvoidEdges() ?: self.rawLayer->getDefaultSymbolAvoidEdges(); + auto propertyValue = self.rawLayer->getSymbolAvoidEdges(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultSymbolAvoidEdges()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -491,21 +539,27 @@ - (void)setSymbolPlacement:(MGLStyleValue *)symbolPlacement { - (MGLStyleValue *)symbolPlacement { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getSymbolPlacement() ?: self.rawLayer->getDefaultSymbolPlacement(); + auto propertyValue = self.rawLayer->getSymbolPlacement(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultSymbolPlacement()); + } return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); } - (void)setSymbolSpacing:(MGLStyleValue *)symbolSpacing { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(symbolSpacing); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(symbolSpacing); self.rawLayer->setSymbolSpacing(mbglValue); } - (MGLStyleValue *)symbolSpacing { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getSymbolSpacing() ?: self.rawLayer->getDefaultSymbolSpacing(); + auto propertyValue = self.rawLayer->getSymbolSpacing(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultSymbolSpacing()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -519,7 +573,10 @@ - (void)setText:(MGLStyleValue *)text { - (MGLStyleValue *)text { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextField() ?: self.rawLayer->getDefaultTextField(); + auto propertyValue = self.rawLayer->getTextField(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextField()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -540,7 +597,10 @@ - (void)setTextAllowsOverlap:(MGLStyleValue *)textAllowsOverlap { - (MGLStyleValue *)textAllowsOverlap { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextAllowOverlap() ?: self.rawLayer->getDefaultTextAllowOverlap(); + auto propertyValue = self.rawLayer->getTextAllowOverlap(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextAllowOverlap()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -561,7 +621,10 @@ - (void)setTextAnchor:(MGLStyleValue *)textAnchor { - (MGLStyleValue *)textAnchor { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextAnchor() ?: self.rawLayer->getDefaultTextAnchor(); + auto propertyValue = self.rawLayer->getTextAnchor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultTextAnchor()); + } return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); } @@ -575,7 +638,10 @@ - (void)setTextFontNames:(MGLStyleValue *> *)textFontNames { - (MGLStyleValue *> *)textFontNames { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextFont() ?: self.rawLayer->getDefaultTextFont(); + auto propertyValue = self.rawLayer->getTextFont(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer, NSArray *, std::string>().toStyleValue(self.rawLayer->getDefaultTextFont()); + } return MGLStyleValueTransformer, NSArray *, std::string>().toStyleValue(propertyValue); } @@ -589,14 +655,17 @@ - (void)setTextFont:(MGLStyleValue *> *)textFont { - (void)setTextFontSize:(MGLStyleValue *)textFontSize { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(textFontSize); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(textFontSize); self.rawLayer->setTextSize(mbglValue); } - (MGLStyleValue *)textFontSize { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextSize() ?: self.rawLayer->getDefaultTextSize(); + auto propertyValue = self.rawLayer->getTextSize(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextSize()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -617,7 +686,10 @@ - (void)setTextIgnoresPlacement:(MGLStyleValue *)textIgnoresPlacemen - (MGLStyleValue *)textIgnoresPlacement { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextIgnorePlacement() ?: self.rawLayer->getDefaultTextIgnorePlacement(); + auto propertyValue = self.rawLayer->getTextIgnorePlacement(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextIgnorePlacement()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -638,7 +710,10 @@ - (void)setTextJustification:(MGLStyleValue *)textJustification { - (MGLStyleValue *)textJustification { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextJustify() ?: self.rawLayer->getDefaultTextJustify(); + auto propertyValue = self.rawLayer->getTextJustify(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultTextJustify()); + } return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); } @@ -652,42 +727,51 @@ - (void)setTextJustify:(MGLStyleValue *)textJustify { - (void)setTextLetterSpacing:(MGLStyleValue *)textLetterSpacing { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(textLetterSpacing); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(textLetterSpacing); self.rawLayer->setTextLetterSpacing(mbglValue); } - (MGLStyleValue *)textLetterSpacing { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextLetterSpacing() ?: self.rawLayer->getDefaultTextLetterSpacing(); + auto propertyValue = self.rawLayer->getTextLetterSpacing(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextLetterSpacing()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setTextLineHeight:(MGLStyleValue *)textLineHeight { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(textLineHeight); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(textLineHeight); self.rawLayer->setTextLineHeight(mbglValue); } - (MGLStyleValue *)textLineHeight { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextLineHeight() ?: self.rawLayer->getDefaultTextLineHeight(); + auto propertyValue = self.rawLayer->getTextLineHeight(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextLineHeight()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setTextOffset:(MGLStyleValue *)textOffset { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer, NSValue *>().toPropertyValue(textOffset); + auto mbglValue = MGLStyleValueTransformer, NSValue *>().toInterpolatablePropertyValue(textOffset); self.rawLayer->setTextOffset(mbglValue); } - (MGLStyleValue *)textOffset { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextOffset() ?: self.rawLayer->getDefaultTextOffset(); + auto propertyValue = self.rawLayer->getTextOffset(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer, NSValue *>().toStyleValue(self.rawLayer->getDefaultTextOffset()); + } return MGLStyleValueTransformer, NSValue *>().toStyleValue(propertyValue); } @@ -701,21 +785,27 @@ - (void)setTextOptional:(MGLStyleValue *)textOptional { - (MGLStyleValue *)isTextOptional { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextOptional() ?: self.rawLayer->getDefaultTextOptional(); + auto propertyValue = self.rawLayer->getTextOptional(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextOptional()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setTextPadding:(MGLStyleValue *)textPadding { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(textPadding); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(textPadding); self.rawLayer->setTextPadding(mbglValue); } - (MGLStyleValue *)textPadding { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextPadding() ?: self.rawLayer->getDefaultTextPadding(); + auto propertyValue = self.rawLayer->getTextPadding(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextPadding()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -729,21 +819,27 @@ - (void)setTextPitchAlignment:(MGLStyleValue *)textPitchAlignment { - (MGLStyleValue *)textPitchAlignment { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextPitchAlignment() ?: self.rawLayer->getDefaultTextPitchAlignment(); + auto propertyValue = self.rawLayer->getTextPitchAlignment(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultTextPitchAlignment()); + } return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); } - (void)setTextRotation:(MGLStyleValue *)textRotation { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(textRotation); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(textRotation); self.rawLayer->setTextRotate(mbglValue); } - (MGLStyleValue *)textRotation { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextRotate() ?: self.rawLayer->getDefaultTextRotate(); + auto propertyValue = self.rawLayer->getTextRotate(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextRotate()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } @@ -764,7 +860,10 @@ - (void)setTextRotationAlignment:(MGLStyleValue *)textRotationAlignme - (MGLStyleValue *)textRotationAlignment { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextRotationAlignment() ?: self.rawLayer->getDefaultTextRotationAlignment(); + auto propertyValue = self.rawLayer->getTextRotationAlignment(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultTextRotationAlignment()); + } return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); } @@ -778,7 +877,10 @@ - (void)setTextTransform:(MGLStyleValue *)textTransform { - (MGLStyleValue *)textTransform { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextTransform() ?: self.rawLayer->getDefaultTextTransform(); + auto propertyValue = self.rawLayer->getTextTransform(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultTextTransform()); + } return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); } @@ -787,84 +889,102 @@ - (void)setTextTransform:(MGLStyleValue *)textTransform { - (void)setIconColor:(MGLStyleValue *)iconColor { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(iconColor); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(iconColor); self.rawLayer->setIconColor(mbglValue); } - (MGLStyleValue *)iconColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconColor() ?: self.rawLayer->getDefaultIconColor(); + auto propertyValue = self.rawLayer->getIconColor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultIconColor()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setIconHaloBlur:(MGLStyleValue *)iconHaloBlur { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(iconHaloBlur); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(iconHaloBlur); self.rawLayer->setIconHaloBlur(mbglValue); } - (MGLStyleValue *)iconHaloBlur { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconHaloBlur() ?: self.rawLayer->getDefaultIconHaloBlur(); + auto propertyValue = self.rawLayer->getIconHaloBlur(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultIconHaloBlur()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setIconHaloColor:(MGLStyleValue *)iconHaloColor { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(iconHaloColor); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(iconHaloColor); self.rawLayer->setIconHaloColor(mbglValue); } - (MGLStyleValue *)iconHaloColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconHaloColor() ?: self.rawLayer->getDefaultIconHaloColor(); + auto propertyValue = self.rawLayer->getIconHaloColor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultIconHaloColor()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setIconHaloWidth:(MGLStyleValue *)iconHaloWidth { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(iconHaloWidth); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(iconHaloWidth); self.rawLayer->setIconHaloWidth(mbglValue); } - (MGLStyleValue *)iconHaloWidth { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconHaloWidth() ?: self.rawLayer->getDefaultIconHaloWidth(); + auto propertyValue = self.rawLayer->getIconHaloWidth(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultIconHaloWidth()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setIconOpacity:(MGLStyleValue *)iconOpacity { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(iconOpacity); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(iconOpacity); self.rawLayer->setIconOpacity(mbglValue); } - (MGLStyleValue *)iconOpacity { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconOpacity() ?: self.rawLayer->getDefaultIconOpacity(); + auto propertyValue = self.rawLayer->getIconOpacity(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultIconOpacity()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setIconTranslation:(MGLStyleValue *)iconTranslation { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer, NSValue *>().toPropertyValue(iconTranslation); + auto mbglValue = MGLStyleValueTransformer, NSValue *>().toInterpolatablePropertyValue(iconTranslation); self.rawLayer->setIconTranslate(mbglValue); } - (MGLStyleValue *)iconTranslation { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconTranslate() ?: self.rawLayer->getDefaultIconTranslate(); + auto propertyValue = self.rawLayer->getIconTranslate(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer, NSValue *>().toStyleValue(self.rawLayer->getDefaultIconTranslate()); + } return MGLStyleValueTransformer, NSValue *>().toStyleValue(propertyValue); } @@ -885,7 +1005,10 @@ - (void)setIconTranslationAnchor:(MGLStyleValue *)iconTranslationAnch - (MGLStyleValue *)iconTranslationAnchor { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getIconTranslateAnchor() ?: self.rawLayer->getDefaultIconTranslateAnchor(); + auto propertyValue = self.rawLayer->getIconTranslateAnchor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultIconTranslateAnchor()); + } return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); } @@ -899,84 +1022,102 @@ - (void)setIconTranslateAnchor:(MGLStyleValue *)iconTranslateAnchor { - (void)setTextColor:(MGLStyleValue *)textColor { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(textColor); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(textColor); self.rawLayer->setTextColor(mbglValue); } - (MGLStyleValue *)textColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextColor() ?: self.rawLayer->getDefaultTextColor(); + auto propertyValue = self.rawLayer->getTextColor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextColor()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setTextHaloBlur:(MGLStyleValue *)textHaloBlur { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(textHaloBlur); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(textHaloBlur); self.rawLayer->setTextHaloBlur(mbglValue); } - (MGLStyleValue *)textHaloBlur { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextHaloBlur() ?: self.rawLayer->getDefaultTextHaloBlur(); + auto propertyValue = self.rawLayer->getTextHaloBlur(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextHaloBlur()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setTextHaloColor:(MGLStyleValue *)textHaloColor { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(textHaloColor); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(textHaloColor); self.rawLayer->setTextHaloColor(mbglValue); } - (MGLStyleValue *)textHaloColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextHaloColor() ?: self.rawLayer->getDefaultTextHaloColor(); + auto propertyValue = self.rawLayer->getTextHaloColor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextHaloColor()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setTextHaloWidth:(MGLStyleValue *)textHaloWidth { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(textHaloWidth); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(textHaloWidth); self.rawLayer->setTextHaloWidth(mbglValue); } - (MGLStyleValue *)textHaloWidth { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextHaloWidth() ?: self.rawLayer->getDefaultTextHaloWidth(); + auto propertyValue = self.rawLayer->getTextHaloWidth(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextHaloWidth()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setTextOpacity:(MGLStyleValue *)textOpacity { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer().toPropertyValue(textOpacity); + auto mbglValue = MGLStyleValueTransformer().toInterpolatablePropertyValue(textOpacity); self.rawLayer->setTextOpacity(mbglValue); } - (MGLStyleValue *)textOpacity { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextOpacity() ?: self.rawLayer->getDefaultTextOpacity(); + auto propertyValue = self.rawLayer->getTextOpacity(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toStyleValue(self.rawLayer->getDefaultTextOpacity()); + } return MGLStyleValueTransformer().toStyleValue(propertyValue); } - (void)setTextTranslation:(MGLStyleValue *)textTranslation { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer, NSValue *>().toPropertyValue(textTranslation); + auto mbglValue = MGLStyleValueTransformer, NSValue *>().toInterpolatablePropertyValue(textTranslation); self.rawLayer->setTextTranslate(mbglValue); } - (MGLStyleValue *)textTranslation { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextTranslate() ?: self.rawLayer->getDefaultTextTranslate(); + auto propertyValue = self.rawLayer->getTextTranslate(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer, NSValue *>().toStyleValue(self.rawLayer->getDefaultTextTranslate()); + } return MGLStyleValueTransformer, NSValue *>().toStyleValue(propertyValue); } @@ -997,7 +1138,10 @@ - (void)setTextTranslationAnchor:(MGLStyleValue *)textTranslationAnch - (MGLStyleValue *)textTranslationAnchor { MGLAssertStyleLayerIsValid(); - auto propertyValue = self.rawLayer->getTextTranslateAnchor() ?: self.rawLayer->getDefaultTextTranslateAnchor(); + auto propertyValue = self.rawLayer->getTextTranslateAnchor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer().toEnumStyleValue(self.rawLayer->getDefaultTextTranslateAnchor()); + } return MGLStyleValueTransformer().toEnumStyleValue(propertyValue); } diff --git a/platform/darwin/test/MGLBackgroundStyleLayerTests.mm b/platform/darwin/test/MGLBackgroundStyleLayerTests.mm index e14d00668e7..40fa8a152fc 100644 --- a/platform/darwin/test/MGLBackgroundStyleLayerTests.mm +++ b/platform/darwin/test/MGLBackgroundStyleLayerTests.mm @@ -1,5 +1,5 @@ // This file is generated. -// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`. #import "MGLStyleLayerTests.h" @@ -28,26 +28,26 @@ - (void)testProperties { @"background-color should be unset initially."); MGLStyleValue *defaultStyleValue = layer.backgroundColor; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; - layer.backgroundColor = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; + layer.backgroundColor = constantStyleValue; mbgl::style::PropertyValue propertyValue = { { 1, 0, 0, 1 } }; XCTAssertEqual(rawLayer->getBackgroundColor(), propertyValue, @"Setting backgroundColor to a constant value should update background-color."); - XCTAssertEqualObjects(layer.backgroundColor, styleValue, + XCTAssertEqualObjects(layer.backgroundColor, constantStyleValue, @"backgroundColor should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.backgroundColor = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.backgroundColor = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, { 1, 0, 0, 1 }}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getBackgroundColor(), propertyValue, - @"Setting backgroundColor to a function should update background-color."); - XCTAssertEqualObjects(layer.backgroundColor, styleValue, - @"backgroundColor should round-trip functions."); + @"Setting backgroundColor to a camera function should update background-color."); + XCTAssertEqualObjects(layer.backgroundColor, functionStyleValue, + @"backgroundColor should round-trip camera functions."); + + layer.backgroundColor = nil; XCTAssertTrue(rawLayer->getBackgroundColor().isUndefined(), @@ -62,26 +62,26 @@ - (void)testProperties { @"background-opacity should be unset initially."); MGLStyleValue *defaultStyleValue = layer.backgroundOpacity; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.backgroundOpacity = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.backgroundOpacity = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getBackgroundOpacity(), propertyValue, @"Setting backgroundOpacity to a constant value should update background-opacity."); - XCTAssertEqualObjects(layer.backgroundOpacity, styleValue, + XCTAssertEqualObjects(layer.backgroundOpacity, constantStyleValue, @"backgroundOpacity should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.backgroundOpacity = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.backgroundOpacity = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getBackgroundOpacity(), propertyValue, - @"Setting backgroundOpacity to a function should update background-opacity."); - XCTAssertEqualObjects(layer.backgroundOpacity, styleValue, - @"backgroundOpacity should round-trip functions."); + @"Setting backgroundOpacity to a camera function should update background-opacity."); + XCTAssertEqualObjects(layer.backgroundOpacity, functionStyleValue, + @"backgroundOpacity should round-trip camera functions."); + + layer.backgroundOpacity = nil; XCTAssertTrue(rawLayer->getBackgroundOpacity().isUndefined(), @@ -96,32 +96,38 @@ - (void)testProperties { @"background-pattern should be unset initially."); MGLStyleValue *defaultStyleValue = layer.backgroundPattern; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@"Background Pattern"]; - layer.backgroundPattern = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@"Background Pattern"]; + layer.backgroundPattern = constantStyleValue; mbgl::style::PropertyValue propertyValue = { "Background Pattern" }; XCTAssertEqual(rawLayer->getBackgroundPattern(), propertyValue, @"Setting backgroundPattern to a constant value should update background-pattern."); - XCTAssertEqualObjects(layer.backgroundPattern, styleValue, + XCTAssertEqualObjects(layer.backgroundPattern, constantStyleValue, @"backgroundPattern should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.backgroundPattern = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.backgroundPattern = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, "Background Pattern"}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getBackgroundPattern(), propertyValue, - @"Setting backgroundPattern to a function should update background-pattern."); - XCTAssertEqualObjects(layer.backgroundPattern, styleValue, - @"backgroundPattern should round-trip functions."); + @"Setting backgroundPattern to a camera function should update background-pattern."); + XCTAssertEqualObjects(layer.backgroundPattern, functionStyleValue, + @"backgroundPattern should round-trip camera functions."); + + layer.backgroundPattern = nil; XCTAssertTrue(rawLayer->getBackgroundPattern().isUndefined(), @"Unsetting backgroundPattern should return background-pattern to the default value."); XCTAssertEqualObjects(layer.backgroundPattern, defaultStyleValue, @"backgroundPattern should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } } diff --git a/platform/darwin/test/MGLCircleStyleLayerTests.mm b/platform/darwin/test/MGLCircleStyleLayerTests.mm index b8eb84a5679..2bf8aab1959 100644 --- a/platform/darwin/test/MGLCircleStyleLayerTests.mm +++ b/platform/darwin/test/MGLCircleStyleLayerTests.mm @@ -1,5 +1,5 @@ // This file is generated. -// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`. #import "MGLStyleLayerTests.h" @@ -49,26 +49,49 @@ - (void)testProperties { @"circle-blur should be unset initially."); MGLStyleValue *defaultStyleValue = layer.circleBlur; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.circleBlur = styleValue; - mbgl::style::PropertyValue propertyValue = { 0xff }; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.circleBlur = constantStyleValue; + mbgl::style::DataDrivenPropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue, @"Setting circleBlur to a constant value should update circle-blur."); - XCTAssertEqualObjects(layer.circleBlur, styleValue, + XCTAssertEqualObjects(layer.circleBlur, constantStyleValue, @"circleBlur should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.circleBlur = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.circleBlur = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { 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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.circleBlur = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, 0xff}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.circleBlur = functionStyleValue; + + mbgl::style::ExponentialStops innerStops = { { {18, 0xff}}, 1.0 }; + std::map> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction { "keyName", compositeStops }; + XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue, - @"Setting circleBlur to a function should update circle-blur."); - XCTAssertEqualObjects(layer.circleBlur, styleValue, - @"circleBlur should round-trip functions."); + @"Setting circleBlur to a composite function should update circle-blur."); + XCTAssertEqualObjects(layer.circleBlur, functionStyleValue, + @"circleBlur should round-trip composite functions."); + layer.circleBlur = nil; XCTAssertTrue(rawLayer->getCircleBlur().isUndefined(), @@ -83,26 +106,49 @@ - (void)testProperties { @"circle-color should be unset initially."); MGLStyleValue *defaultStyleValue = layer.circleColor; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; - layer.circleColor = styleValue; - mbgl::style::PropertyValue propertyValue = { { 1, 0, 0, 1 } }; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; + layer.circleColor = constantStyleValue; + mbgl::style::DataDrivenPropertyValue propertyValue = { { 1, 0, 0, 1 } }; XCTAssertEqual(rawLayer->getCircleColor(), propertyValue, @"Setting circleColor to a constant value should update circle-color."); - XCTAssertEqualObjects(layer.circleColor, styleValue, + XCTAssertEqualObjects(layer.circleColor, constantStyleValue, @"circleColor should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.circleColor = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.circleColor = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, { 1, 0, 0, 1 }}} }; + propertyValue = mbgl::style::CameraFunction { 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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.circleColor = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.circleColor = functionStyleValue; + + mbgl::style::ExponentialStops innerStops = { { {18, { 1, 0, 0, 1 }}}, 1.0 }; + std::map> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction { "keyName", compositeStops }; + XCTAssertEqual(rawLayer->getCircleColor(), propertyValue, - @"Setting circleColor to a function should update circle-color."); - XCTAssertEqualObjects(layer.circleColor, styleValue, - @"circleColor should round-trip functions."); + @"Setting circleColor to a composite function should update circle-color."); + XCTAssertEqualObjects(layer.circleColor, functionStyleValue, + @"circleColor should round-trip composite functions."); + layer.circleColor = nil; XCTAssertTrue(rawLayer->getCircleColor().isUndefined(), @@ -117,26 +163,49 @@ - (void)testProperties { @"circle-opacity should be unset initially."); MGLStyleValue *defaultStyleValue = layer.circleOpacity; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.circleOpacity = styleValue; - mbgl::style::PropertyValue propertyValue = { 0xff }; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.circleOpacity = constantStyleValue; + mbgl::style::DataDrivenPropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue, @"Setting circleOpacity to a constant value should update circle-opacity."); - XCTAssertEqualObjects(layer.circleOpacity, styleValue, + XCTAssertEqualObjects(layer.circleOpacity, constantStyleValue, @"circleOpacity should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.circleOpacity = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.circleOpacity = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { 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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.circleOpacity = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, 0xff}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.circleOpacity = functionStyleValue; + + mbgl::style::ExponentialStops innerStops = { { {18, 0xff}}, 1.0 }; + std::map> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction { "keyName", compositeStops }; + XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue, - @"Setting circleOpacity to a function should update circle-opacity."); - XCTAssertEqualObjects(layer.circleOpacity, styleValue, - @"circleOpacity should round-trip functions."); + @"Setting circleOpacity to a composite function should update circle-opacity."); + XCTAssertEqualObjects(layer.circleOpacity, functionStyleValue, + @"circleOpacity should round-trip composite functions."); + layer.circleOpacity = nil; XCTAssertTrue(rawLayer->getCircleOpacity().isUndefined(), @@ -151,26 +220,49 @@ - (void)testProperties { @"circle-radius should be unset initially."); MGLStyleValue *defaultStyleValue = layer.circleRadius; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.circleRadius = styleValue; - mbgl::style::PropertyValue propertyValue = { 0xff }; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.circleRadius = constantStyleValue; + mbgl::style::DataDrivenPropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue, @"Setting circleRadius to a constant value should update circle-radius."); - XCTAssertEqualObjects(layer.circleRadius, styleValue, + XCTAssertEqualObjects(layer.circleRadius, constantStyleValue, @"circleRadius should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.circleRadius = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.circleRadius = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { 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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.circleRadius = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, 0xff}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.circleRadius = functionStyleValue; + + mbgl::style::ExponentialStops innerStops = { { {18, 0xff}}, 1.0 }; + std::map> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction { "keyName", compositeStops }; + XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue, - @"Setting circleRadius to a function should update circle-radius."); - XCTAssertEqualObjects(layer.circleRadius, styleValue, - @"circleRadius should round-trip functions."); + @"Setting circleRadius to a composite function should update circle-radius."); + XCTAssertEqualObjects(layer.circleRadius, functionStyleValue, + @"circleRadius should round-trip composite functions."); + layer.circleRadius = nil; XCTAssertTrue(rawLayer->getCircleRadius().isUndefined(), @@ -185,32 +277,38 @@ - (void)testProperties { @"circle-pitch-scale should be unset initially."); MGLStyleValue *defaultStyleValue = layer.circleScaleAlignment; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentViewport]]; - layer.circleScaleAlignment = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentViewport]]; + layer.circleScaleAlignment = constantStyleValue; mbgl::style::PropertyValue propertyValue = { mbgl::style::CirclePitchScaleType::Viewport }; XCTAssertEqual(rawLayer->getCirclePitchScale(), propertyValue, @"Setting circleScaleAlignment to a constant value should update circle-pitch-scale."); - XCTAssertEqualObjects(layer.circleScaleAlignment, styleValue, + XCTAssertEqualObjects(layer.circleScaleAlignment, constantStyleValue, @"circleScaleAlignment should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.circleScaleAlignment = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.circleScaleAlignment = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::CirclePitchScaleType::Viewport}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getCirclePitchScale(), propertyValue, - @"Setting circleScaleAlignment to a function should update circle-pitch-scale."); - XCTAssertEqualObjects(layer.circleScaleAlignment, styleValue, - @"circleScaleAlignment should round-trip functions."); + @"Setting circleScaleAlignment to a camera function should update circle-pitch-scale."); + XCTAssertEqualObjects(layer.circleScaleAlignment, functionStyleValue, + @"circleScaleAlignment should round-trip camera functions."); + + layer.circleScaleAlignment = nil; XCTAssertTrue(rawLayer->getCirclePitchScale().isUndefined(), @"Unsetting circleScaleAlignment should return circle-pitch-scale to the default value."); XCTAssertEqualObjects(layer.circleScaleAlignment, defaultStyleValue, @"circleScaleAlignment should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // circle-stroke-color @@ -219,26 +317,49 @@ - (void)testProperties { @"circle-stroke-color should be unset initially."); MGLStyleValue *defaultStyleValue = layer.circleStrokeColor; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; - layer.circleStrokeColor = styleValue; - mbgl::style::PropertyValue propertyValue = { { 1, 0, 0, 1 } }; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; + layer.circleStrokeColor = constantStyleValue; + mbgl::style::DataDrivenPropertyValue propertyValue = { { 1, 0, 0, 1 } }; XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue, @"Setting circleStrokeColor to a constant value should update circle-stroke-color."); - XCTAssertEqualObjects(layer.circleStrokeColor, styleValue, + XCTAssertEqualObjects(layer.circleStrokeColor, constantStyleValue, @"circleStrokeColor should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.circleStrokeColor = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.circleStrokeColor = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, { 1, 0, 0, 1 }}} }; + propertyValue = mbgl::style::CameraFunction { 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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.circleStrokeColor = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.circleStrokeColor = functionStyleValue; + + mbgl::style::ExponentialStops innerStops = { { {18, { 1, 0, 0, 1 }}}, 1.0 }; + std::map> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction { "keyName", compositeStops }; + XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue, - @"Setting circleStrokeColor to a function should update circle-stroke-color."); - XCTAssertEqualObjects(layer.circleStrokeColor, styleValue, - @"circleStrokeColor should round-trip functions."); + @"Setting circleStrokeColor to a composite function should update circle-stroke-color."); + XCTAssertEqualObjects(layer.circleStrokeColor, functionStyleValue, + @"circleStrokeColor should round-trip composite functions."); + layer.circleStrokeColor = nil; XCTAssertTrue(rawLayer->getCircleStrokeColor().isUndefined(), @@ -253,26 +374,49 @@ - (void)testProperties { @"circle-stroke-opacity should be unset initially."); MGLStyleValue *defaultStyleValue = layer.circleStrokeOpacity; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.circleStrokeOpacity = styleValue; - mbgl::style::PropertyValue propertyValue = { 0xff }; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.circleStrokeOpacity = constantStyleValue; + mbgl::style::DataDrivenPropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue, @"Setting circleStrokeOpacity to a constant value should update circle-stroke-opacity."); - XCTAssertEqualObjects(layer.circleStrokeOpacity, styleValue, + XCTAssertEqualObjects(layer.circleStrokeOpacity, constantStyleValue, @"circleStrokeOpacity should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.circleStrokeOpacity = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.circleStrokeOpacity = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { 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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.circleStrokeOpacity = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, 0xff}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.circleStrokeOpacity = functionStyleValue; + + mbgl::style::ExponentialStops innerStops = { { {18, 0xff}}, 1.0 }; + std::map> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction { "keyName", compositeStops }; + XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue, - @"Setting circleStrokeOpacity to a function should update circle-stroke-opacity."); - XCTAssertEqualObjects(layer.circleStrokeOpacity, styleValue, - @"circleStrokeOpacity should round-trip functions."); + @"Setting circleStrokeOpacity to a composite function should update circle-stroke-opacity."); + XCTAssertEqualObjects(layer.circleStrokeOpacity, functionStyleValue, + @"circleStrokeOpacity should round-trip composite functions."); + layer.circleStrokeOpacity = nil; XCTAssertTrue(rawLayer->getCircleStrokeOpacity().isUndefined(), @@ -287,26 +431,49 @@ - (void)testProperties { @"circle-stroke-width should be unset initially."); MGLStyleValue *defaultStyleValue = layer.circleStrokeWidth; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.circleStrokeWidth = styleValue; - mbgl::style::PropertyValue propertyValue = { 0xff }; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.circleStrokeWidth = constantStyleValue; + mbgl::style::DataDrivenPropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue, @"Setting circleStrokeWidth to a constant value should update circle-stroke-width."); - XCTAssertEqualObjects(layer.circleStrokeWidth, styleValue, + XCTAssertEqualObjects(layer.circleStrokeWidth, constantStyleValue, @"circleStrokeWidth should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.circleStrokeWidth = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.circleStrokeWidth = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { 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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.circleStrokeWidth = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, 0xff}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.circleStrokeWidth = functionStyleValue; + + mbgl::style::ExponentialStops innerStops = { { {18, 0xff}}, 1.0 }; + std::map> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction { "keyName", compositeStops }; + XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue, - @"Setting circleStrokeWidth to a function should update circle-stroke-width."); - XCTAssertEqualObjects(layer.circleStrokeWidth, styleValue, - @"circleStrokeWidth should round-trip functions."); + @"Setting circleStrokeWidth to a composite function should update circle-stroke-width."); + XCTAssertEqualObjects(layer.circleStrokeWidth, functionStyleValue, + @"circleStrokeWidth should round-trip composite functions."); + layer.circleStrokeWidth = nil; XCTAssertTrue(rawLayer->getCircleStrokeWidth().isUndefined(), @@ -321,32 +488,32 @@ - (void)testProperties { @"circle-translate should be unset initially."); MGLStyleValue *defaultStyleValue = layer.circleTranslation; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue: + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue: #if TARGET_OS_IPHONE [NSValue valueWithCGVector:CGVectorMake(1, 1)] #else [NSValue valueWithMGLVector:CGVectorMake(1, -1)] #endif ]; - layer.circleTranslation = styleValue; + layer.circleTranslation = constantStyleValue; mbgl::style::PropertyValue> propertyValue = { { 1, 1 } }; XCTAssertEqual(rawLayer->getCircleTranslate(), propertyValue, @"Setting circleTranslation to a constant value should update circle-translate."); - XCTAssertEqualObjects(layer.circleTranslation, styleValue, + XCTAssertEqualObjects(layer.circleTranslation, constantStyleValue, @"circleTranslation should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.circleTranslation = styleValue; - propertyValue = { mbgl::style::Function> { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.circleTranslation = functionStyleValue; + + mbgl::style::IntervalStops> intervalStops = { {{18, { 1, 1 }}} }; + propertyValue = mbgl::style::CameraFunction> { intervalStops }; + XCTAssertEqual(rawLayer->getCircleTranslate(), propertyValue, - @"Setting circleTranslation to a function should update circle-translate."); - XCTAssertEqualObjects(layer.circleTranslation, styleValue, - @"circleTranslation should round-trip functions."); + @"Setting circleTranslation to a camera function should update circle-translate."); + XCTAssertEqualObjects(layer.circleTranslation, functionStyleValue, + @"circleTranslation should round-trip camera functions."); + + layer.circleTranslation = nil; XCTAssertTrue(rawLayer->getCircleTranslate().isUndefined(), @@ -361,32 +528,38 @@ - (void)testProperties { @"circle-translate-anchor should be unset initially."); MGLStyleValue *defaultStyleValue = layer.circleTranslationAnchor; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLCircleTranslationAnchor:MGLCircleTranslationAnchorViewport]]; - layer.circleTranslationAnchor = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLCircleTranslationAnchor:MGLCircleTranslationAnchorViewport]]; + layer.circleTranslationAnchor = constantStyleValue; mbgl::style::PropertyValue propertyValue = { mbgl::style::TranslateAnchorType::Viewport }; XCTAssertEqual(rawLayer->getCircleTranslateAnchor(), propertyValue, @"Setting circleTranslationAnchor to a constant value should update circle-translate-anchor."); - XCTAssertEqualObjects(layer.circleTranslationAnchor, styleValue, + XCTAssertEqualObjects(layer.circleTranslationAnchor, constantStyleValue, @"circleTranslationAnchor should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.circleTranslationAnchor = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.circleTranslationAnchor = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getCircleTranslateAnchor(), propertyValue, - @"Setting circleTranslationAnchor to a function should update circle-translate-anchor."); - XCTAssertEqualObjects(layer.circleTranslationAnchor, styleValue, - @"circleTranslationAnchor should round-trip functions."); + @"Setting circleTranslationAnchor to a camera function should update circle-translate-anchor."); + XCTAssertEqualObjects(layer.circleTranslationAnchor, functionStyleValue, + @"circleTranslationAnchor should round-trip camera functions."); + + layer.circleTranslationAnchor = nil; XCTAssertTrue(rawLayer->getCircleTranslateAnchor().isUndefined(), @"Unsetting circleTranslationAnchor should return circle-translate-anchor to the default value."); XCTAssertEqualObjects(layer.circleTranslationAnchor, defaultStyleValue, @"circleTranslationAnchor should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } } diff --git a/platform/darwin/test/MGLFillStyleLayerTests.mm b/platform/darwin/test/MGLFillStyleLayerTests.mm index afc3260a286..9aeba531747 100644 --- a/platform/darwin/test/MGLFillStyleLayerTests.mm +++ b/platform/darwin/test/MGLFillStyleLayerTests.mm @@ -1,5 +1,5 @@ // This file is generated. -// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`. #import "MGLStyleLayerTests.h" @@ -49,32 +49,38 @@ - (void)testProperties { @"fill-antialias should be unset initially."); MGLStyleValue *defaultStyleValue = layer.fillAntialiased; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@NO]; - layer.fillAntialiased = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@NO]; + layer.fillAntialiased = constantStyleValue; mbgl::style::PropertyValue propertyValue = { false }; XCTAssertEqual(rawLayer->getFillAntialias(), propertyValue, @"Setting fillAntialiased to a constant value should update fill-antialias."); - XCTAssertEqualObjects(layer.fillAntialiased, styleValue, + XCTAssertEqualObjects(layer.fillAntialiased, constantStyleValue, @"fillAntialiased should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.fillAntialiased = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.fillAntialiased = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, false}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getFillAntialias(), propertyValue, - @"Setting fillAntialiased to a function should update fill-antialias."); - XCTAssertEqualObjects(layer.fillAntialiased, styleValue, - @"fillAntialiased should round-trip functions."); + @"Setting fillAntialiased to a camera function should update fill-antialias."); + XCTAssertEqualObjects(layer.fillAntialiased, functionStyleValue, + @"fillAntialiased should round-trip camera functions."); + + layer.fillAntialiased = nil; XCTAssertTrue(rawLayer->getFillAntialias().isUndefined(), @"Unsetting fillAntialiased should return fill-antialias to the default value."); XCTAssertEqualObjects(layer.fillAntialiased, defaultStyleValue, @"fillAntialiased should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // fill-color @@ -83,26 +89,49 @@ - (void)testProperties { @"fill-color should be unset initially."); MGLStyleValue *defaultStyleValue = layer.fillColor; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; - layer.fillColor = styleValue; - mbgl::style::PropertyValue propertyValue = { { 1, 0, 0, 1 } }; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; + layer.fillColor = constantStyleValue; + mbgl::style::DataDrivenPropertyValue propertyValue = { { 1, 0, 0, 1 } }; XCTAssertEqual(rawLayer->getFillColor(), propertyValue, @"Setting fillColor to a constant value should update fill-color."); - XCTAssertEqualObjects(layer.fillColor, styleValue, + XCTAssertEqualObjects(layer.fillColor, constantStyleValue, @"fillColor should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.fillColor = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.fillColor = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, { 1, 0, 0, 1 }}} }; + propertyValue = mbgl::style::CameraFunction { 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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.fillColor = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.fillColor = functionStyleValue; + + mbgl::style::ExponentialStops innerStops = { { {18, { 1, 0, 0, 1 }}}, 1.0 }; + std::map> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction { "keyName", compositeStops }; + XCTAssertEqual(rawLayer->getFillColor(), propertyValue, - @"Setting fillColor to a function should update fill-color."); - XCTAssertEqualObjects(layer.fillColor, styleValue, - @"fillColor should round-trip functions."); + @"Setting fillColor to a composite function should update fill-color."); + XCTAssertEqualObjects(layer.fillColor, functionStyleValue, + @"fillColor should round-trip composite functions."); + layer.fillColor = nil; XCTAssertTrue(rawLayer->getFillColor().isUndefined(), @@ -117,26 +146,49 @@ - (void)testProperties { @"fill-opacity should be unset initially."); MGLStyleValue *defaultStyleValue = layer.fillOpacity; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.fillOpacity = styleValue; - mbgl::style::PropertyValue propertyValue = { 0xff }; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.fillOpacity = constantStyleValue; + mbgl::style::DataDrivenPropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue, @"Setting fillOpacity to a constant value should update fill-opacity."); - XCTAssertEqualObjects(layer.fillOpacity, styleValue, + XCTAssertEqualObjects(layer.fillOpacity, constantStyleValue, @"fillOpacity should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.fillOpacity = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.fillOpacity = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { 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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.fillOpacity = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, 0xff}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.fillOpacity = functionStyleValue; + + mbgl::style::ExponentialStops innerStops = { { {18, 0xff}}, 1.0 }; + std::map> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction { "keyName", compositeStops }; + XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue, - @"Setting fillOpacity to a function should update fill-opacity."); - XCTAssertEqualObjects(layer.fillOpacity, styleValue, - @"fillOpacity should round-trip functions."); + @"Setting fillOpacity to a composite function should update fill-opacity."); + XCTAssertEqualObjects(layer.fillOpacity, functionStyleValue, + @"fillOpacity should round-trip composite functions."); + layer.fillOpacity = nil; XCTAssertTrue(rawLayer->getFillOpacity().isUndefined(), @@ -151,26 +203,49 @@ - (void)testProperties { @"fill-outline-color should be unset initially."); MGLStyleValue *defaultStyleValue = layer.fillOutlineColor; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; - layer.fillOutlineColor = styleValue; - mbgl::style::PropertyValue propertyValue = { { 1, 0, 0, 1 } }; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; + layer.fillOutlineColor = constantStyleValue; + mbgl::style::DataDrivenPropertyValue propertyValue = { { 1, 0, 0, 1 } }; XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue, @"Setting fillOutlineColor to a constant value should update fill-outline-color."); - XCTAssertEqualObjects(layer.fillOutlineColor, styleValue, + XCTAssertEqualObjects(layer.fillOutlineColor, constantStyleValue, @"fillOutlineColor should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.fillOutlineColor = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.fillOutlineColor = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, { 1, 0, 0, 1 }}} }; + propertyValue = mbgl::style::CameraFunction { 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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.fillOutlineColor = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.fillOutlineColor = functionStyleValue; + + mbgl::style::ExponentialStops innerStops = { { {18, { 1, 0, 0, 1 }}}, 1.0 }; + std::map> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction { "keyName", compositeStops }; + XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue, - @"Setting fillOutlineColor to a function should update fill-outline-color."); - XCTAssertEqualObjects(layer.fillOutlineColor, styleValue, - @"fillOutlineColor should round-trip functions."); + @"Setting fillOutlineColor to a composite function should update fill-outline-color."); + XCTAssertEqualObjects(layer.fillOutlineColor, functionStyleValue, + @"fillOutlineColor should round-trip composite functions."); + layer.fillOutlineColor = nil; XCTAssertTrue(rawLayer->getFillOutlineColor().isUndefined(), @@ -185,32 +260,38 @@ - (void)testProperties { @"fill-pattern should be unset initially."); MGLStyleValue *defaultStyleValue = layer.fillPattern; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@"Fill Pattern"]; - layer.fillPattern = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@"Fill Pattern"]; + layer.fillPattern = constantStyleValue; mbgl::style::PropertyValue propertyValue = { "Fill Pattern" }; XCTAssertEqual(rawLayer->getFillPattern(), propertyValue, @"Setting fillPattern to a constant value should update fill-pattern."); - XCTAssertEqualObjects(layer.fillPattern, styleValue, + XCTAssertEqualObjects(layer.fillPattern, constantStyleValue, @"fillPattern should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.fillPattern = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.fillPattern = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, "Fill Pattern"}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getFillPattern(), propertyValue, - @"Setting fillPattern to a function should update fill-pattern."); - XCTAssertEqualObjects(layer.fillPattern, styleValue, - @"fillPattern should round-trip functions."); + @"Setting fillPattern to a camera function should update fill-pattern."); + XCTAssertEqualObjects(layer.fillPattern, functionStyleValue, + @"fillPattern should round-trip camera functions."); + + layer.fillPattern = nil; XCTAssertTrue(rawLayer->getFillPattern().isUndefined(), @"Unsetting fillPattern should return fill-pattern to the default value."); XCTAssertEqualObjects(layer.fillPattern, defaultStyleValue, @"fillPattern should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // fill-translate @@ -219,32 +300,32 @@ - (void)testProperties { @"fill-translate should be unset initially."); MGLStyleValue *defaultStyleValue = layer.fillTranslation; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue: + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue: #if TARGET_OS_IPHONE [NSValue valueWithCGVector:CGVectorMake(1, 1)] #else [NSValue valueWithMGLVector:CGVectorMake(1, -1)] #endif ]; - layer.fillTranslation = styleValue; + layer.fillTranslation = constantStyleValue; mbgl::style::PropertyValue> propertyValue = { { 1, 1 } }; XCTAssertEqual(rawLayer->getFillTranslate(), propertyValue, @"Setting fillTranslation to a constant value should update fill-translate."); - XCTAssertEqualObjects(layer.fillTranslation, styleValue, + XCTAssertEqualObjects(layer.fillTranslation, constantStyleValue, @"fillTranslation should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.fillTranslation = styleValue; - propertyValue = { mbgl::style::Function> { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.fillTranslation = functionStyleValue; + + mbgl::style::IntervalStops> intervalStops = { {{18, { 1, 1 }}} }; + propertyValue = mbgl::style::CameraFunction> { intervalStops }; + XCTAssertEqual(rawLayer->getFillTranslate(), propertyValue, - @"Setting fillTranslation to a function should update fill-translate."); - XCTAssertEqualObjects(layer.fillTranslation, styleValue, - @"fillTranslation should round-trip functions."); + @"Setting fillTranslation to a camera function should update fill-translate."); + XCTAssertEqualObjects(layer.fillTranslation, functionStyleValue, + @"fillTranslation should round-trip camera functions."); + + layer.fillTranslation = nil; XCTAssertTrue(rawLayer->getFillTranslate().isUndefined(), @@ -259,32 +340,38 @@ - (void)testProperties { @"fill-translate-anchor should be unset initially."); MGLStyleValue *defaultStyleValue = layer.fillTranslationAnchor; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLFillTranslationAnchor:MGLFillTranslationAnchorViewport]]; - layer.fillTranslationAnchor = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLFillTranslationAnchor:MGLFillTranslationAnchorViewport]]; + layer.fillTranslationAnchor = constantStyleValue; mbgl::style::PropertyValue propertyValue = { mbgl::style::TranslateAnchorType::Viewport }; XCTAssertEqual(rawLayer->getFillTranslateAnchor(), propertyValue, @"Setting fillTranslationAnchor to a constant value should update fill-translate-anchor."); - XCTAssertEqualObjects(layer.fillTranslationAnchor, styleValue, + XCTAssertEqualObjects(layer.fillTranslationAnchor, constantStyleValue, @"fillTranslationAnchor should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.fillTranslationAnchor = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.fillTranslationAnchor = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getFillTranslateAnchor(), propertyValue, - @"Setting fillTranslationAnchor to a function should update fill-translate-anchor."); - XCTAssertEqualObjects(layer.fillTranslationAnchor, styleValue, - @"fillTranslationAnchor should round-trip functions."); + @"Setting fillTranslationAnchor to a camera function should update fill-translate-anchor."); + XCTAssertEqualObjects(layer.fillTranslationAnchor, functionStyleValue, + @"fillTranslationAnchor should round-trip camera functions."); + + layer.fillTranslationAnchor = nil; XCTAssertTrue(rawLayer->getFillTranslateAnchor().isUndefined(), @"Unsetting fillTranslationAnchor should return fill-translate-anchor to the default value."); XCTAssertEqualObjects(layer.fillTranslationAnchor, defaultStyleValue, @"fillTranslationAnchor should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } } diff --git a/platform/darwin/test/MGLLineStyleLayerTests.mm b/platform/darwin/test/MGLLineStyleLayerTests.mm index 3d0a4133e97..e150dca0e4e 100644 --- a/platform/darwin/test/MGLLineStyleLayerTests.mm +++ b/platform/darwin/test/MGLLineStyleLayerTests.mm @@ -1,5 +1,5 @@ // This file is generated. -// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`. #import "MGLStyleLayerTests.h" @@ -49,32 +49,38 @@ - (void)testProperties { @"line-cap should be unset initially."); MGLStyleValue *defaultStyleValue = layer.lineCap; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLLineCap:MGLLineCapSquare]]; - layer.lineCap = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLLineCap:MGLLineCapSquare]]; + layer.lineCap = constantStyleValue; mbgl::style::PropertyValue propertyValue = { mbgl::style::LineCapType::Square }; XCTAssertEqual(rawLayer->getLineCap(), propertyValue, @"Setting lineCap to a constant value should update line-cap."); - XCTAssertEqualObjects(layer.lineCap, styleValue, + XCTAssertEqualObjects(layer.lineCap, constantStyleValue, @"lineCap should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.lineCap = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.lineCap = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::LineCapType::Square}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getLineCap(), propertyValue, - @"Setting lineCap to a function should update line-cap."); - XCTAssertEqualObjects(layer.lineCap, styleValue, - @"lineCap should round-trip functions."); + @"Setting lineCap to a camera function should update line-cap."); + XCTAssertEqualObjects(layer.lineCap, functionStyleValue, + @"lineCap should round-trip camera functions."); + + layer.lineCap = nil; XCTAssertTrue(rawLayer->getLineCap().isUndefined(), @"Unsetting lineCap should return line-cap to the default value."); XCTAssertEqualObjects(layer.lineCap, defaultStyleValue, @"lineCap should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // line-join @@ -83,32 +89,38 @@ - (void)testProperties { @"line-join should be unset initially."); MGLStyleValue *defaultStyleValue = layer.lineJoin; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLLineJoin:MGLLineJoinMiter]]; - layer.lineJoin = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLLineJoin:MGLLineJoinMiter]]; + layer.lineJoin = constantStyleValue; mbgl::style::PropertyValue propertyValue = { mbgl::style::LineJoinType::Miter }; XCTAssertEqual(rawLayer->getLineJoin(), propertyValue, @"Setting lineJoin to a constant value should update line-join."); - XCTAssertEqualObjects(layer.lineJoin, styleValue, + XCTAssertEqualObjects(layer.lineJoin, constantStyleValue, @"lineJoin should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.lineJoin = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.lineJoin = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::LineJoinType::Miter}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getLineJoin(), propertyValue, - @"Setting lineJoin to a function should update line-join."); - XCTAssertEqualObjects(layer.lineJoin, styleValue, - @"lineJoin should round-trip functions."); + @"Setting lineJoin to a camera function should update line-join."); + XCTAssertEqualObjects(layer.lineJoin, functionStyleValue, + @"lineJoin should round-trip camera functions."); + + layer.lineJoin = nil; XCTAssertTrue(rawLayer->getLineJoin().isUndefined(), @"Unsetting lineJoin should return line-join to the default value."); XCTAssertEqualObjects(layer.lineJoin, defaultStyleValue, @"lineJoin should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.lineJoin = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.lineJoin = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); } // line-miter-limit @@ -117,26 +129,26 @@ - (void)testProperties { @"line-miter-limit should be unset initially."); MGLStyleValue *defaultStyleValue = layer.lineMiterLimit; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.lineMiterLimit = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.lineMiterLimit = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getLineMiterLimit(), propertyValue, @"Setting lineMiterLimit to a constant value should update line-miter-limit."); - XCTAssertEqualObjects(layer.lineMiterLimit, styleValue, + XCTAssertEqualObjects(layer.lineMiterLimit, constantStyleValue, @"lineMiterLimit should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.lineMiterLimit = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.lineMiterLimit = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getLineMiterLimit(), propertyValue, - @"Setting lineMiterLimit to a function should update line-miter-limit."); - XCTAssertEqualObjects(layer.lineMiterLimit, styleValue, - @"lineMiterLimit should round-trip functions."); + @"Setting lineMiterLimit to a camera function should update line-miter-limit."); + XCTAssertEqualObjects(layer.lineMiterLimit, functionStyleValue, + @"lineMiterLimit should round-trip camera functions."); + + layer.lineMiterLimit = nil; XCTAssertTrue(rawLayer->getLineMiterLimit().isUndefined(), @@ -151,26 +163,26 @@ - (void)testProperties { @"line-round-limit should be unset initially."); MGLStyleValue *defaultStyleValue = layer.lineRoundLimit; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.lineRoundLimit = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.lineRoundLimit = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getLineRoundLimit(), propertyValue, @"Setting lineRoundLimit to a constant value should update line-round-limit."); - XCTAssertEqualObjects(layer.lineRoundLimit, styleValue, + XCTAssertEqualObjects(layer.lineRoundLimit, constantStyleValue, @"lineRoundLimit should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.lineRoundLimit = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.lineRoundLimit = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getLineRoundLimit(), propertyValue, - @"Setting lineRoundLimit to a function should update line-round-limit."); - XCTAssertEqualObjects(layer.lineRoundLimit, styleValue, - @"lineRoundLimit should round-trip functions."); + @"Setting lineRoundLimit to a camera function should update line-round-limit."); + XCTAssertEqualObjects(layer.lineRoundLimit, functionStyleValue, + @"lineRoundLimit should round-trip camera functions."); + + layer.lineRoundLimit = nil; XCTAssertTrue(rawLayer->getLineRoundLimit().isUndefined(), @@ -185,26 +197,49 @@ - (void)testProperties { @"line-blur should be unset initially."); MGLStyleValue *defaultStyleValue = layer.lineBlur; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.lineBlur = styleValue; - mbgl::style::PropertyValue propertyValue = { 0xff }; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.lineBlur = constantStyleValue; + mbgl::style::DataDrivenPropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getLineBlur(), propertyValue, @"Setting lineBlur to a constant value should update line-blur."); - XCTAssertEqualObjects(layer.lineBlur, styleValue, + XCTAssertEqualObjects(layer.lineBlur, constantStyleValue, @"lineBlur should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.lineBlur = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.lineBlur = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { 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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.lineBlur = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, 0xff}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "keyName", exponentialStops }; + XCTAssertEqual(rawLayer->getLineBlur(), propertyValue, - @"Setting lineBlur to a function should update line-blur."); - XCTAssertEqualObjects(layer.lineBlur, styleValue, - @"lineBlur should round-trip functions."); + @"Setting lineBlur to a source function should update line-blur."); + XCTAssertEqualObjects(layer.lineBlur, functionStyleValue, + @"lineBlur should round-trip source functions."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.lineBlur = functionStyleValue; + + mbgl::style::ExponentialStops innerStops = { { {18, 0xff}}, 1.0 }; + std::map> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction { "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."); + layer.lineBlur = nil; XCTAssertTrue(rawLayer->getLineBlur().isUndefined(), @@ -219,26 +254,49 @@ - (void)testProperties { @"line-color should be unset initially."); MGLStyleValue *defaultStyleValue = layer.lineColor; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; - layer.lineColor = styleValue; - mbgl::style::PropertyValue propertyValue = { { 1, 0, 0, 1 } }; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; + layer.lineColor = constantStyleValue; + mbgl::style::DataDrivenPropertyValue propertyValue = { { 1, 0, 0, 1 } }; XCTAssertEqual(rawLayer->getLineColor(), propertyValue, @"Setting lineColor to a constant value should update line-color."); - XCTAssertEqualObjects(layer.lineColor, styleValue, + XCTAssertEqualObjects(layer.lineColor, constantStyleValue, @"lineColor should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.lineColor = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.lineColor = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, { 1, 0, 0, 1 }}} }; + propertyValue = mbgl::style::CameraFunction { 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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.lineColor = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.lineColor = functionStyleValue; + + mbgl::style::ExponentialStops innerStops = { { {18, { 1, 0, 0, 1 }}}, 1.0 }; + std::map> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction { "keyName", compositeStops }; + XCTAssertEqual(rawLayer->getLineColor(), propertyValue, - @"Setting lineColor to a function should update line-color."); - XCTAssertEqualObjects(layer.lineColor, styleValue, - @"lineColor should round-trip functions."); + @"Setting lineColor to a composite function should update line-color."); + XCTAssertEqualObjects(layer.lineColor, functionStyleValue, + @"lineColor should round-trip composite functions."); + layer.lineColor = nil; XCTAssertTrue(rawLayer->getLineColor().isUndefined(), @@ -253,32 +311,38 @@ - (void)testProperties { @"line-dasharray should be unset initially."); MGLStyleValue *> *defaultStyleValue = layer.lineDashPattern; - MGLStyleValue *> *styleValue = [MGLStyleValue *> valueWithRawValue:@[@1, @2]]; - layer.lineDashPattern = styleValue; + MGLStyleValue *> *constantStyleValue = [MGLStyleValue *> valueWithRawValue:@[@1, @2]]; + layer.lineDashPattern = constantStyleValue; mbgl::style::PropertyValue> propertyValue = { {1, 2} }; XCTAssertEqual(rawLayer->getLineDasharray(), propertyValue, @"Setting lineDashPattern to a constant value should update line-dasharray."); - XCTAssertEqualObjects(layer.lineDashPattern, styleValue, + XCTAssertEqualObjects(layer.lineDashPattern, constantStyleValue, @"lineDashPattern should round-trip constant values."); - styleValue = [MGLStyleValue *> valueWithStops:@{ - @18: styleValue, - }]; - layer.lineDashPattern = styleValue; - propertyValue = { mbgl::style::Function> { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue *> * functionStyleValue = [MGLStyleValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.lineDashPattern = functionStyleValue; + + mbgl::style::IntervalStops> intervalStops = { {{18, {1, 2}}} }; + propertyValue = mbgl::style::CameraFunction> { intervalStops }; + XCTAssertEqual(rawLayer->getLineDasharray(), propertyValue, - @"Setting lineDashPattern to a function should update line-dasharray."); - XCTAssertEqualObjects(layer.lineDashPattern, styleValue, - @"lineDashPattern should round-trip functions."); + @"Setting lineDashPattern to a camera function should update line-dasharray."); + XCTAssertEqualObjects(layer.lineDashPattern, functionStyleValue, + @"lineDashPattern should round-trip camera functions."); + + layer.lineDashPattern = nil; XCTAssertTrue(rawLayer->getLineDasharray().isUndefined(), @"Unsetting lineDashPattern should return line-dasharray to the default value."); XCTAssertEqualObjects(layer.lineDashPattern, defaultStyleValue, @"lineDashPattern should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue *> 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 *> 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"); } // line-gap-width @@ -287,26 +351,49 @@ - (void)testProperties { @"line-gap-width should be unset initially."); MGLStyleValue *defaultStyleValue = layer.lineGapWidth; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.lineGapWidth = styleValue; - mbgl::style::PropertyValue propertyValue = { 0xff }; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.lineGapWidth = constantStyleValue; + mbgl::style::DataDrivenPropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue, @"Setting lineGapWidth to a constant value should update line-gap-width."); - XCTAssertEqualObjects(layer.lineGapWidth, styleValue, + XCTAssertEqualObjects(layer.lineGapWidth, constantStyleValue, @"lineGapWidth should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.lineGapWidth = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.lineGapWidth = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { 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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.lineGapWidth = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, 0xff}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "keyName", exponentialStops }; + XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue, - @"Setting lineGapWidth to a function should update line-gap-width."); - XCTAssertEqualObjects(layer.lineGapWidth, styleValue, - @"lineGapWidth should round-trip functions."); + @"Setting lineGapWidth to a source function should update line-gap-width."); + XCTAssertEqualObjects(layer.lineGapWidth, functionStyleValue, + @"lineGapWidth should round-trip source functions."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.lineGapWidth = functionStyleValue; + + mbgl::style::ExponentialStops innerStops = { { {18, 0xff}}, 1.0 }; + std::map> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction { "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."); + layer.lineGapWidth = nil; XCTAssertTrue(rawLayer->getLineGapWidth().isUndefined(), @@ -321,26 +408,49 @@ - (void)testProperties { @"line-offset should be unset initially."); MGLStyleValue *defaultStyleValue = layer.lineOffset; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.lineOffset = styleValue; - mbgl::style::PropertyValue propertyValue = { 0xff }; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.lineOffset = constantStyleValue; + mbgl::style::DataDrivenPropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getLineOffset(), propertyValue, @"Setting lineOffset to a constant value should update line-offset."); - XCTAssertEqualObjects(layer.lineOffset, styleValue, + XCTAssertEqualObjects(layer.lineOffset, constantStyleValue, @"lineOffset should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.lineOffset = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.lineOffset = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getLineOffset(), propertyValue, - @"Setting lineOffset to a function should update line-offset."); - XCTAssertEqualObjects(layer.lineOffset, styleValue, - @"lineOffset should round-trip functions."); + @"Setting lineOffset to a camera function should update line-offset."); + XCTAssertEqualObjects(layer.lineOffset, functionStyleValue, + @"lineOffset should round-trip camera functions."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.lineOffset = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, 0xff}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.lineOffset = functionStyleValue; + + mbgl::style::ExponentialStops innerStops = { { {18, 0xff}}, 1.0 }; + std::map> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction { "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."); + layer.lineOffset = nil; XCTAssertTrue(rawLayer->getLineOffset().isUndefined(), @@ -355,26 +465,49 @@ - (void)testProperties { @"line-opacity should be unset initially."); MGLStyleValue *defaultStyleValue = layer.lineOpacity; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.lineOpacity = styleValue; - mbgl::style::PropertyValue propertyValue = { 0xff }; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.lineOpacity = constantStyleValue; + mbgl::style::DataDrivenPropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue, @"Setting lineOpacity to a constant value should update line-opacity."); - XCTAssertEqualObjects(layer.lineOpacity, styleValue, + XCTAssertEqualObjects(layer.lineOpacity, constantStyleValue, @"lineOpacity should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.lineOpacity = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.lineOpacity = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue, - @"Setting lineOpacity to a function should update line-opacity."); - XCTAssertEqualObjects(layer.lineOpacity, styleValue, - @"lineOpacity should round-trip functions."); + @"Setting lineOpacity to a camera function should update line-opacity."); + XCTAssertEqualObjects(layer.lineOpacity, functionStyleValue, + @"lineOpacity should round-trip camera functions."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.lineOpacity = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, 0xff}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.lineOpacity = functionStyleValue; + + mbgl::style::ExponentialStops innerStops = { { {18, 0xff}}, 1.0 }; + std::map> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction { "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."); + layer.lineOpacity = nil; XCTAssertTrue(rawLayer->getLineOpacity().isUndefined(), @@ -389,32 +522,38 @@ - (void)testProperties { @"line-pattern should be unset initially."); MGLStyleValue *defaultStyleValue = layer.linePattern; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@"Line Pattern"]; - layer.linePattern = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@"Line Pattern"]; + layer.linePattern = constantStyleValue; mbgl::style::PropertyValue propertyValue = { "Line Pattern" }; XCTAssertEqual(rawLayer->getLinePattern(), propertyValue, @"Setting linePattern to a constant value should update line-pattern."); - XCTAssertEqualObjects(layer.linePattern, styleValue, + XCTAssertEqualObjects(layer.linePattern, constantStyleValue, @"linePattern should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.linePattern = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.linePattern = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, "Line Pattern"}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getLinePattern(), propertyValue, - @"Setting linePattern to a function should update line-pattern."); - XCTAssertEqualObjects(layer.linePattern, styleValue, - @"linePattern should round-trip functions."); + @"Setting linePattern to a camera function should update line-pattern."); + XCTAssertEqualObjects(layer.linePattern, functionStyleValue, + @"linePattern should round-trip camera functions."); + + layer.linePattern = nil; XCTAssertTrue(rawLayer->getLinePattern().isUndefined(), @"Unsetting linePattern should return line-pattern to the default value."); XCTAssertEqualObjects(layer.linePattern, defaultStyleValue, @"linePattern should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // line-translate @@ -423,32 +562,32 @@ - (void)testProperties { @"line-translate should be unset initially."); MGLStyleValue *defaultStyleValue = layer.lineTranslation; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue: + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue: #if TARGET_OS_IPHONE [NSValue valueWithCGVector:CGVectorMake(1, 1)] #else [NSValue valueWithMGLVector:CGVectorMake(1, -1)] #endif ]; - layer.lineTranslation = styleValue; + layer.lineTranslation = constantStyleValue; mbgl::style::PropertyValue> propertyValue = { { 1, 1 } }; XCTAssertEqual(rawLayer->getLineTranslate(), propertyValue, @"Setting lineTranslation to a constant value should update line-translate."); - XCTAssertEqualObjects(layer.lineTranslation, styleValue, + XCTAssertEqualObjects(layer.lineTranslation, constantStyleValue, @"lineTranslation should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.lineTranslation = styleValue; - propertyValue = { mbgl::style::Function> { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.lineTranslation = functionStyleValue; + + mbgl::style::IntervalStops> intervalStops = { {{18, { 1, 1 }}} }; + propertyValue = mbgl::style::CameraFunction> { intervalStops }; + XCTAssertEqual(rawLayer->getLineTranslate(), propertyValue, - @"Setting lineTranslation to a function should update line-translate."); - XCTAssertEqualObjects(layer.lineTranslation, styleValue, - @"lineTranslation should round-trip functions."); + @"Setting lineTranslation to a camera function should update line-translate."); + XCTAssertEqualObjects(layer.lineTranslation, functionStyleValue, + @"lineTranslation should round-trip camera functions."); + + layer.lineTranslation = nil; XCTAssertTrue(rawLayer->getLineTranslate().isUndefined(), @@ -463,32 +602,38 @@ - (void)testProperties { @"line-translate-anchor should be unset initially."); MGLStyleValue *defaultStyleValue = layer.lineTranslationAnchor; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLLineTranslationAnchor:MGLLineTranslationAnchorViewport]]; - layer.lineTranslationAnchor = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLLineTranslationAnchor:MGLLineTranslationAnchorViewport]]; + layer.lineTranslationAnchor = constantStyleValue; mbgl::style::PropertyValue propertyValue = { mbgl::style::TranslateAnchorType::Viewport }; XCTAssertEqual(rawLayer->getLineTranslateAnchor(), propertyValue, @"Setting lineTranslationAnchor to a constant value should update line-translate-anchor."); - XCTAssertEqualObjects(layer.lineTranslationAnchor, styleValue, + XCTAssertEqualObjects(layer.lineTranslationAnchor, constantStyleValue, @"lineTranslationAnchor should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.lineTranslationAnchor = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.lineTranslationAnchor = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getLineTranslateAnchor(), propertyValue, - @"Setting lineTranslationAnchor to a function should update line-translate-anchor."); - XCTAssertEqualObjects(layer.lineTranslationAnchor, styleValue, - @"lineTranslationAnchor should round-trip functions."); + @"Setting lineTranslationAnchor to a camera function should update line-translate-anchor."); + XCTAssertEqualObjects(layer.lineTranslationAnchor, functionStyleValue, + @"lineTranslationAnchor should round-trip camera functions."); + + layer.lineTranslationAnchor = nil; XCTAssertTrue(rawLayer->getLineTranslateAnchor().isUndefined(), @"Unsetting lineTranslationAnchor should return line-translate-anchor to the default value."); XCTAssertEqualObjects(layer.lineTranslationAnchor, defaultStyleValue, @"lineTranslationAnchor should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // line-width @@ -497,26 +642,26 @@ - (void)testProperties { @"line-width should be unset initially."); MGLStyleValue *defaultStyleValue = layer.lineWidth; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.lineWidth = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.lineWidth = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getLineWidth(), propertyValue, @"Setting lineWidth to a constant value should update line-width."); - XCTAssertEqualObjects(layer.lineWidth, styleValue, + XCTAssertEqualObjects(layer.lineWidth, constantStyleValue, @"lineWidth should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.lineWidth = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.lineWidth = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getLineWidth(), propertyValue, - @"Setting lineWidth to a function should update line-width."); - XCTAssertEqualObjects(layer.lineWidth, styleValue, - @"lineWidth should round-trip functions."); + @"Setting lineWidth to a camera function should update line-width."); + XCTAssertEqualObjects(layer.lineWidth, functionStyleValue, + @"lineWidth should round-trip camera functions."); + + layer.lineWidth = nil; XCTAssertTrue(rawLayer->getLineWidth().isUndefined(), diff --git a/platform/darwin/test/MGLRasterStyleLayerTests.mm b/platform/darwin/test/MGLRasterStyleLayerTests.mm index debccd1ef6c..d8efefc9d57 100644 --- a/platform/darwin/test/MGLRasterStyleLayerTests.mm +++ b/platform/darwin/test/MGLRasterStyleLayerTests.mm @@ -1,5 +1,5 @@ // This file is generated. -// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`. #import "MGLStyleLayerTests.h" @@ -31,26 +31,26 @@ - (void)testProperties { @"raster-brightness-max should be unset initially."); MGLStyleValue *defaultStyleValue = layer.maximumRasterBrightness; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.maximumRasterBrightness = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.maximumRasterBrightness = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getRasterBrightnessMax(), propertyValue, @"Setting maximumRasterBrightness to a constant value should update raster-brightness-max."); - XCTAssertEqualObjects(layer.maximumRasterBrightness, styleValue, + XCTAssertEqualObjects(layer.maximumRasterBrightness, constantStyleValue, @"maximumRasterBrightness should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.maximumRasterBrightness = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.maximumRasterBrightness = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getRasterBrightnessMax(), propertyValue, - @"Setting maximumRasterBrightness to a function should update raster-brightness-max."); - XCTAssertEqualObjects(layer.maximumRasterBrightness, styleValue, - @"maximumRasterBrightness should round-trip functions."); + @"Setting maximumRasterBrightness to a camera function should update raster-brightness-max."); + XCTAssertEqualObjects(layer.maximumRasterBrightness, functionStyleValue, + @"maximumRasterBrightness should round-trip camera functions."); + + layer.maximumRasterBrightness = nil; XCTAssertTrue(rawLayer->getRasterBrightnessMax().isUndefined(), @@ -65,26 +65,26 @@ - (void)testProperties { @"raster-brightness-min should be unset initially."); MGLStyleValue *defaultStyleValue = layer.minimumRasterBrightness; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.minimumRasterBrightness = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.minimumRasterBrightness = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getRasterBrightnessMin(), propertyValue, @"Setting minimumRasterBrightness to a constant value should update raster-brightness-min."); - XCTAssertEqualObjects(layer.minimumRasterBrightness, styleValue, + XCTAssertEqualObjects(layer.minimumRasterBrightness, constantStyleValue, @"minimumRasterBrightness should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.minimumRasterBrightness = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.minimumRasterBrightness = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getRasterBrightnessMin(), propertyValue, - @"Setting minimumRasterBrightness to a function should update raster-brightness-min."); - XCTAssertEqualObjects(layer.minimumRasterBrightness, styleValue, - @"minimumRasterBrightness should round-trip functions."); + @"Setting minimumRasterBrightness to a camera function should update raster-brightness-min."); + XCTAssertEqualObjects(layer.minimumRasterBrightness, functionStyleValue, + @"minimumRasterBrightness should round-trip camera functions."); + + layer.minimumRasterBrightness = nil; XCTAssertTrue(rawLayer->getRasterBrightnessMin().isUndefined(), @@ -99,26 +99,26 @@ - (void)testProperties { @"raster-contrast should be unset initially."); MGLStyleValue *defaultStyleValue = layer.rasterContrast; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.rasterContrast = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.rasterContrast = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getRasterContrast(), propertyValue, @"Setting rasterContrast to a constant value should update raster-contrast."); - XCTAssertEqualObjects(layer.rasterContrast, styleValue, + XCTAssertEqualObjects(layer.rasterContrast, constantStyleValue, @"rasterContrast should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.rasterContrast = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.rasterContrast = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getRasterContrast(), propertyValue, - @"Setting rasterContrast to a function should update raster-contrast."); - XCTAssertEqualObjects(layer.rasterContrast, styleValue, - @"rasterContrast should round-trip functions."); + @"Setting rasterContrast to a camera function should update raster-contrast."); + XCTAssertEqualObjects(layer.rasterContrast, functionStyleValue, + @"rasterContrast should round-trip camera functions."); + + layer.rasterContrast = nil; XCTAssertTrue(rawLayer->getRasterContrast().isUndefined(), @@ -133,26 +133,26 @@ - (void)testProperties { @"raster-fade-duration should be unset initially."); MGLStyleValue *defaultStyleValue = layer.rasterFadeDuration; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.rasterFadeDuration = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.rasterFadeDuration = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getRasterFadeDuration(), propertyValue, @"Setting rasterFadeDuration to a constant value should update raster-fade-duration."); - XCTAssertEqualObjects(layer.rasterFadeDuration, styleValue, + XCTAssertEqualObjects(layer.rasterFadeDuration, constantStyleValue, @"rasterFadeDuration should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.rasterFadeDuration = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.rasterFadeDuration = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getRasterFadeDuration(), propertyValue, - @"Setting rasterFadeDuration to a function should update raster-fade-duration."); - XCTAssertEqualObjects(layer.rasterFadeDuration, styleValue, - @"rasterFadeDuration should round-trip functions."); + @"Setting rasterFadeDuration to a camera function should update raster-fade-duration."); + XCTAssertEqualObjects(layer.rasterFadeDuration, functionStyleValue, + @"rasterFadeDuration should round-trip camera functions."); + + layer.rasterFadeDuration = nil; XCTAssertTrue(rawLayer->getRasterFadeDuration().isUndefined(), @@ -167,26 +167,26 @@ - (void)testProperties { @"raster-hue-rotate should be unset initially."); MGLStyleValue *defaultStyleValue = layer.rasterHueRotation; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.rasterHueRotation = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.rasterHueRotation = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getRasterHueRotate(), propertyValue, @"Setting rasterHueRotation to a constant value should update raster-hue-rotate."); - XCTAssertEqualObjects(layer.rasterHueRotation, styleValue, + XCTAssertEqualObjects(layer.rasterHueRotation, constantStyleValue, @"rasterHueRotation should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.rasterHueRotation = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.rasterHueRotation = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getRasterHueRotate(), propertyValue, - @"Setting rasterHueRotation to a function should update raster-hue-rotate."); - XCTAssertEqualObjects(layer.rasterHueRotation, styleValue, - @"rasterHueRotation should round-trip functions."); + @"Setting rasterHueRotation to a camera function should update raster-hue-rotate."); + XCTAssertEqualObjects(layer.rasterHueRotation, functionStyleValue, + @"rasterHueRotation should round-trip camera functions."); + + layer.rasterHueRotation = nil; XCTAssertTrue(rawLayer->getRasterHueRotate().isUndefined(), @@ -201,26 +201,26 @@ - (void)testProperties { @"raster-opacity should be unset initially."); MGLStyleValue *defaultStyleValue = layer.rasterOpacity; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.rasterOpacity = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.rasterOpacity = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getRasterOpacity(), propertyValue, @"Setting rasterOpacity to a constant value should update raster-opacity."); - XCTAssertEqualObjects(layer.rasterOpacity, styleValue, + XCTAssertEqualObjects(layer.rasterOpacity, constantStyleValue, @"rasterOpacity should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.rasterOpacity = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.rasterOpacity = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getRasterOpacity(), propertyValue, - @"Setting rasterOpacity to a function should update raster-opacity."); - XCTAssertEqualObjects(layer.rasterOpacity, styleValue, - @"rasterOpacity should round-trip functions."); + @"Setting rasterOpacity to a camera function should update raster-opacity."); + XCTAssertEqualObjects(layer.rasterOpacity, functionStyleValue, + @"rasterOpacity should round-trip camera functions."); + + layer.rasterOpacity = nil; XCTAssertTrue(rawLayer->getRasterOpacity().isUndefined(), @@ -235,26 +235,26 @@ - (void)testProperties { @"raster-saturation should be unset initially."); MGLStyleValue *defaultStyleValue = layer.rasterSaturation; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.rasterSaturation = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.rasterSaturation = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getRasterSaturation(), propertyValue, @"Setting rasterSaturation to a constant value should update raster-saturation."); - XCTAssertEqualObjects(layer.rasterSaturation, styleValue, + XCTAssertEqualObjects(layer.rasterSaturation, constantStyleValue, @"rasterSaturation should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.rasterSaturation = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.rasterSaturation = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getRasterSaturation(), propertyValue, - @"Setting rasterSaturation to a function should update raster-saturation."); - XCTAssertEqualObjects(layer.rasterSaturation, styleValue, - @"rasterSaturation should round-trip functions."); + @"Setting rasterSaturation to a camera function should update raster-saturation."); + XCTAssertEqualObjects(layer.rasterSaturation, functionStyleValue, + @"rasterSaturation should round-trip camera functions."); + + layer.rasterSaturation = nil; XCTAssertTrue(rawLayer->getRasterSaturation().isUndefined(), diff --git a/platform/darwin/test/MGLStyleLayerTests.mm.ejs b/platform/darwin/test/MGLStyleLayerTests.mm.ejs index d47f1fbe257..baa5337430d 100644 --- a/platform/darwin/test/MGLStyleLayerTests.mm.ejs +++ b/platform/darwin/test/MGLStyleLayerTests.mm.ejs @@ -4,7 +4,7 @@ const enumProperties = locals.enumProperties; -%> // This file is generated. -// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`. #import "MGLStyleLayerTests.h" @@ -61,26 +61,54 @@ @"<%- originalPropertyName(property) %> should be unset initially."); MGLStyleValue<<%- propertyType(property) %>> *defaultStyleValue = layer.<%- objCName(property) %>; - MGLStyleValue<<%- propertyType(property) %>> *styleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithRawValue:<%- objCTestValue(property, type, 3) %>]; - layer.<%- objCName(property) %> = styleValue; + MGLStyleValue<<%- propertyType(property) %>> *constantStyleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithRawValue:<%- objCTestValue(property, type, 3) %>]; + layer.<%- objCName(property) %> = constantStyleValue; +<% 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) %>, styleValue, + XCTAssertEqualObjects(layer.<%- objCName(property) %>, constantStyleValue, @"<%- objCName(property) %> should round-trip constant values."); - styleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithStops:@{ - @18: styleValue, - }]; - layer.<%- objCName(property) %> = styleValue; - propertyValue = { mbgl::style::Function<<%- mbglType(property) %>> { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + 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) %>}} }; + 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."); + +<% if (property["property-function"]) { -%> + functionStyleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.<%- objCName(property) %> = functionStyleValue; + + 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 function should update <%- originalPropertyName(property) %>."); - XCTAssertEqualObjects(layer.<%- objCName(property) %>, styleValue, - @"<%- objCName(property) %> should round-trip functions."); + @"Setting <%- objCName(property) %> to a source function should update <%- originalPropertyName(property) %>."); + XCTAssertEqualObjects(layer.<%- objCName(property) %>, functionStyleValue, + @"<%- objCName(property) %> should round-trip source functions."); + + functionStyleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.<%- objCName(property) %> = functionStyleValue; + + mbgl::style::ExponentialStops<<%- mbglType(property) %>> innerStops = { { {18, <%- mbglTestValue(property, type) %>}}, 1.0 }; + std::map>> compositeStops = { {10.0, innerStops} }; + + 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."); +<% } -%> <% if (!property.required) { -%> layer.<%- objCName(property) %> = nil; @@ -88,6 +116,14 @@ @"Unsetting <%- objCName(property) %> should return <%- originalPropertyName(property) %> to the default value."); XCTAssertEqualObjects(layer.<%- objCName(property) %>, defaultStyleValue, @"<%- objCName(property) %> should return the default value after being unset."); +<% } -%> +<% if (property["function"] == "piecewise-constant") { -%> + + 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"); <% } -%> } <% } -%> diff --git a/platform/darwin/test/MGLStyleValueTests.swift b/platform/darwin/test/MGLStyleValueTests.swift index 18b6a901de0..28ff2ec86e0 100644 --- a/platform/darwin/test/MGLStyleValueTests.swift +++ b/platform/darwin/test/MGLStyleValueTests.swift @@ -5,8 +5,9 @@ import Mapbox extension MGLStyleValueTests { func testConstantValues() { - let shapeSource = MGLShapeSource(identifier: "test", shape: nil, options: nil) - let symbolStyleLayer = MGLSymbolStyleLayer(identifier: "test", source: shapeSource) + 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 = MGLStyleConstantValue(rawValue: true) @@ -19,20 +20,287 @@ extension MGLStyleValueTests { // String symbolStyleLayer.text = MGLStyleConstantValue(rawValue: "{name}") XCTAssertEqual((symbolStyleLayer.text as! MGLStyleConstantValue).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(rawValue: circleTranslationValueOne) + circleStyleLayer.circleTranslation = expectedCircleTranslationValue + XCTAssertEqual(circleStyleLayer.circleTranslation, expectedCircleTranslationValue) + + // non-data-driven (enumeration property value), set to constant style value + let expectedCircleScaleAlignmentValue = MGLStyleValue(rawValue: NSValue(mglCircleScaleAlignment: .map)) + circleStyleLayer.circleScaleAlignment = expectedCircleScaleAlignmentValue + XCTAssertEqual(circleStyleLayer.circleScaleAlignment, expectedCircleScaleAlignmentValue) } - - func testFunctions() { + + func testDeprecatedFunctions() { let shapeSource = MGLShapeSource(identifier: "test", shape: nil, options: nil) - let symbolStyleLayer = MGLSymbolStyleLayer(identifier: "test", source: shapeSource) - - // Boolean + let symbolStyleLayer = MGLSymbolStyleLayer(identifier: "symbolLayer", source: shapeSource) + + // deprecated function, stops with float values + let iconHaloBlurStyleValue = MGLStyleValue(interpolationBase: 1.0, stops: [1: MGLStyleValue(rawValue: 0), + 2: MGLStyleValue(rawValue: 1), + 3: MGLStyleValue(rawValue: 2), + 4: MGLStyleValue(rawValue: 3)]) + symbolStyleLayer.iconHaloBlur = iconHaloBlurStyleValue + XCTAssertEqual(symbolStyleLayer.iconHaloBlur!, iconHaloBlurStyleValue) + + // deprecated function, stops with boolean values let stops: [NSNumber: MGLStyleValue] = [ 1: MGLStyleValue(rawValue: true), 2: MGLStyleValue(rawValue: false), 3: MGLStyleValue(rawValue: true), 4: MGLStyleValue(rawValue: false), + ] + let iconAllowsOverlapStyleValue = MGLStyleValue(interpolationBase: 1, stops: stops) + symbolStyleLayer.iconAllowsOverlap = iconAllowsOverlapStyleValue + // iconAllowsOverlap is boolean so mgl and mbgl conversions will coerce the developers stops into interval stops + let expectedIconAllowsOverlapStyleValue = MGLStyleValue( + interpolationMode: .interval, + cameraStops: stops, + options: nil + ) + XCTAssertEqual(symbolStyleLayer.iconAllowsOverlap, expectedIconAllowsOverlapStyleValue) + } + + 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 = [ + 0: MGLStyleValue(rawValue: circleTranslationValueOne), + 10: MGLStyleValue(rawValue: circleTranslationValueTwo) + ] + + // non-data-driven (interpolatable property value), camera function with CGVector (NSValue) stop values + let expectedCircleTranslationValue = MGLStyleValue( + 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 = [ + 0: MGLStyleValue(rawValue: NSValue(mglCircleScaleAlignment: .map)), + 10: MGLStyleValue(rawValue: NSValue(mglCircleScaleAlignment: .viewport)) + ] + let expectedCircleScaleAlignmentValue = MGLStyleValue( + 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) + + #if os(iOS) || os(watchOS) || os(tvOS) + + // data-driven, camera function with exponential color stop values + let redGreenStops = [ + 0: MGLStyleValue(rawValue: .red), + 10: MGLStyleValue(rawValue: .red), + 15: MGLStyleValue(rawValue: .green) ] - symbolStyleLayer.iconAllowsOverlap = MGLStyleFunction(interpolationBase: 1, stops: stops) - XCTAssertEqual((symbolStyleLayer.iconAllowsOverlap as! MGLStyleFunction), MGLStyleFunction(interpolationBase: 1, stops: stops)) + let expectedCircleColorValue = MGLStyleValue( + interpolationMode: .exponential, + cameraStops: redGreenStops, + options: [.interpolationBase: 10.0] + ) + circleStyleLayer.circleColor = expectedCircleColorValue + XCTAssertEqual(circleStyleLayer.circleColor, expectedCircleColorValue) + + // data-driven, source function with categorical color stop values with string attribute keys + let redOnlyStops = [ + "red": MGLStyleValue(rawValue: .red) + ] + let expectedRedCategoricalValue = MGLStyleValue( + interpolationMode: .categorical, + sourceStops: redOnlyStops, + attributeName: "red", + options: [.defaultValue: MGLStyleValue(rawValue: .cyan)] + ) + circleStyleLayer.circleColor = expectedRedCategoricalValue + XCTAssertEqual(circleStyleLayer.circleColor, expectedRedCategoricalValue) + + // data-driven, source function with categorical color stop values with integer attribute keys + let greenOrangeStops = [ + 0: MGLStyleValue(rawValue: .green), + 100: MGLStyleValue(rawValue: .orange) + ] + let expectedGreenOrangeCategoricalValue = MGLStyleValue( + interpolationMode: .categorical, + sourceStops: greenOrangeStops, + attributeName: "temp", + options: [.defaultValue: MGLStyleValue(rawValue: .red)] + ) + circleStyleLayer.circleColor = expectedGreenOrangeCategoricalValue + XCTAssertEqual(circleStyleLayer.circleColor, expectedGreenOrangeCategoricalValue) + + // data-driven, source function with exponential color stop values + let expectedRedGreenSourceExponentialValue = MGLStyleValue( + interpolationMode: .exponential, + sourceStops: redGreenStops, + attributeName: "temp", + options: nil + ) + circleStyleLayer.circleColor = expectedRedGreenSourceExponentialValue + XCTAssertEqual(circleStyleLayer.circleColor, expectedRedGreenSourceExponentialValue) + + // data-driven, identity source function + let expectedSourceIdentityValue = MGLStyleValue( + interpolationMode: .identity, + sourceStops: nil, + attributeName: "size", + options: nil + ) + circleStyleLayer.circleColor = expectedSourceIdentityValue + XCTAssertEqual(circleStyleLayer.circleColor, expectedSourceIdentityValue) + + #elseif os(macOS) + + // data-driven, camera function with exponential color stop values + let redGreenStops = [ + 0: MGLStyleValue(rawValue: .red), + 10: MGLStyleValue(rawValue: .red), + 15: MGLStyleValue(rawValue: .green) + ] + let expectedCircleColorValue = MGLStyleValue( + interpolationMode: .exponential, + cameraStops: redGreenStops, + options: [.interpolationBase: 10.0] + ) + circleStyleLayer.circleColor = expectedCircleColorValue + XCTAssertEqual(circleStyleLayer.circleColor, expectedCircleColorValue) + + // data-driven, source function with categorical color stop values with string typed keys + let redOnlyStops = [ + "red": MGLStyleValue(rawValue: .red) + ] + let expectedRedCategoricalValue = MGLStyleValue( + interpolationMode: .categorical, + + sourceStops: redOnlyStops, + attributeName: "red", + options: [.defaultValue: MGLStyleValue(rawValue: .cyan)] + ) + circleStyleLayer.circleColor = expectedRedCategoricalValue + XCTAssertEqual(circleStyleLayer.circleColor, expectedRedCategoricalValue) + + // data-driven, source function with categorical color stop values with integer attribute keys + let greenOrangeStops = [ + 0: MGLStyleValue(rawValue: .green), + 100: MGLStyleValue(rawValue: .orange) + ] + let expectedGreenOrangeCategoricalValue = MGLStyleValue( + interpolationMode: .categorical, + sourceStops: greenOrangeStops, + attributeName: "temp", + options: [.defaultValue: MGLStyleValue(rawValue: .red)] + ) + circleStyleLayer.circleColor = expectedGreenOrangeCategoricalValue + XCTAssertEqual(circleStyleLayer.circleColor, expectedGreenOrangeCategoricalValue) + + // data-driven, source function with exponential color stop values + let expectedRedGreenSourceExponentialValue = MGLStyleValue( + interpolationMode: .exponential, + sourceStops: redGreenStops, + attributeName: "temp", + options: nil + ) + circleStyleLayer.circleColor = expectedRedGreenSourceExponentialValue + XCTAssertEqual(circleStyleLayer.circleColor, expectedRedGreenSourceExponentialValue) + + // data-driven, identity source function + let expectedSourceIdentityValue = MGLStyleValue( + interpolationMode: .identity, + sourceStops: nil, + attributeName: "size", + options: nil + ) + circleStyleLayer.circleColor = expectedSourceIdentityValue + XCTAssertEqual(circleStyleLayer.circleColor, expectedSourceIdentityValue) + + #endif + + // data-driven, source function with categorical color stop values with boolean attribute keys + let booleanCategoricalStops = [ + false: MGLStyleValue(rawValue: 0), + true: MGLStyleValue(rawValue: 2) + ] + let expectedCircleBlurCategoricalValue = MGLStyleValue( + interpolationMode: .categorical, + sourceStops: booleanCategoricalStops, + attributeName: "fuzzy", + options: [.defaultValue: MGLStyleValue(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(rawValue: 5) + let mediumRadius = MGLStyleValue(rawValue: 10) + let largeRadius = MGLStyleValue(rawValue: 20) + let radiusCompositeCategoricalStops: [NSNumber: [String: MGLStyleValue]] = [ + 0: ["green": smallRadius], + 10: ["green": smallRadius], + 15: ["green": largeRadius], + 20: ["green": largeRadius] + ] + let defaultRadius = MGLStyleValue(rawValue: 2) + let expectedCompositeCategoricalValue = MGLStyleValue( + interpolationMode: .categorical, + compositeStops: radiusCompositeCategoricalStops, + attributeName: "color", + options: [.defaultValue: defaultRadius] + ) + circleStyleLayer.circleRadius = expectedCompositeCategoricalValue + XCTAssertEqual(circleStyleLayer.circleRadius, expectedCompositeCategoricalValue) + + // data-driven, composite function with inner exponential color stop values nested in outer camera stops + let radiusCompositeExponentialOrIntervalStops: [NSNumber: [NSNumber: MGLStyleValue]] = [ + 0: [0: smallRadius], + 10: [200: smallRadius], + 20: [200: largeRadius] + ] + let expectedCompositeExponentialValue = MGLStyleValue( + interpolationMode: .exponential, + compositeStops: radiusCompositeExponentialOrIntervalStops, + attributeName: "temp", + options: [.defaultValue: mediumRadius] + ) + circleStyleLayer.circleRadius = expectedCompositeExponentialValue + XCTAssertEqual(circleStyleLayer.circleRadius, expectedCompositeExponentialValue) + + // get a value back + if let returnedCircleRadius = circleStyleLayer.circleRadius as? MGLCompositeStyleFunction { + if let returnedStops = returnedCircleRadius.stops as NSDictionary? as? [NSNumber: [NSNumber: MGLStyleValue]] { + let lhs: MGLStyleValue = returnedStops[0]!.values.first! + let rhs: MGLStyleValue = 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( + interpolationMode: .interval, + compositeStops: radiusCompositeExponentialOrIntervalStops, + attributeName: "temp", + options: nil + ) + circleStyleLayer.circleRadius = expectedCompositeIntervalValue + XCTAssertEqual(circleStyleLayer.circleRadius, expectedCompositeIntervalValue) } } diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.mm b/platform/darwin/test/MGLSymbolStyleLayerTests.mm index 202cbe4e9d4..badd62e7093 100644 --- a/platform/darwin/test/MGLSymbolStyleLayerTests.mm +++ b/platform/darwin/test/MGLSymbolStyleLayerTests.mm @@ -1,5 +1,5 @@ // This file is generated. -// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`. #import "MGLStyleLayerTests.h" @@ -49,32 +49,38 @@ - (void)testProperties { @"icon-allow-overlap should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconAllowsOverlap; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@YES]; - layer.iconAllowsOverlap = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@YES]; + layer.iconAllowsOverlap = constantStyleValue; mbgl::style::PropertyValue propertyValue = { true }; XCTAssertEqual(rawLayer->getIconAllowOverlap(), propertyValue, @"Setting iconAllowsOverlap to a constant value should update icon-allow-overlap."); - XCTAssertEqualObjects(layer.iconAllowsOverlap, styleValue, + XCTAssertEqualObjects(layer.iconAllowsOverlap, constantStyleValue, @"iconAllowsOverlap should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconAllowsOverlap = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconAllowsOverlap = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, true}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getIconAllowOverlap(), propertyValue, - @"Setting iconAllowsOverlap to a function should update icon-allow-overlap."); - XCTAssertEqualObjects(layer.iconAllowsOverlap, styleValue, - @"iconAllowsOverlap should round-trip functions."); + @"Setting iconAllowsOverlap to a camera function should update icon-allow-overlap."); + XCTAssertEqualObjects(layer.iconAllowsOverlap, functionStyleValue, + @"iconAllowsOverlap should round-trip camera functions."); + + layer.iconAllowsOverlap = nil; XCTAssertTrue(rawLayer->getIconAllowOverlap().isUndefined(), @"Unsetting iconAllowsOverlap should return icon-allow-overlap to the default value."); XCTAssertEqualObjects(layer.iconAllowsOverlap, defaultStyleValue, @"iconAllowsOverlap should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // icon-ignore-placement @@ -83,32 +89,38 @@ - (void)testProperties { @"icon-ignore-placement should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconIgnoresPlacement; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@YES]; - layer.iconIgnoresPlacement = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@YES]; + layer.iconIgnoresPlacement = constantStyleValue; mbgl::style::PropertyValue propertyValue = { true }; XCTAssertEqual(rawLayer->getIconIgnorePlacement(), propertyValue, @"Setting iconIgnoresPlacement to a constant value should update icon-ignore-placement."); - XCTAssertEqualObjects(layer.iconIgnoresPlacement, styleValue, + XCTAssertEqualObjects(layer.iconIgnoresPlacement, constantStyleValue, @"iconIgnoresPlacement should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconIgnoresPlacement = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconIgnoresPlacement = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, true}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getIconIgnorePlacement(), propertyValue, - @"Setting iconIgnoresPlacement to a function should update icon-ignore-placement."); - XCTAssertEqualObjects(layer.iconIgnoresPlacement, styleValue, - @"iconIgnoresPlacement should round-trip functions."); + @"Setting iconIgnoresPlacement to a camera function should update icon-ignore-placement."); + XCTAssertEqualObjects(layer.iconIgnoresPlacement, functionStyleValue, + @"iconIgnoresPlacement should round-trip camera functions."); + + layer.iconIgnoresPlacement = nil; XCTAssertTrue(rawLayer->getIconIgnorePlacement().isUndefined(), @"Unsetting iconIgnoresPlacement should return icon-ignore-placement to the default value."); XCTAssertEqualObjects(layer.iconIgnoresPlacement, defaultStyleValue, @"iconIgnoresPlacement should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // icon-image @@ -117,32 +129,38 @@ - (void)testProperties { @"icon-image should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconImageName; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@"Icon Image"]; - layer.iconImageName = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@"Icon Image"]; + layer.iconImageName = constantStyleValue; mbgl::style::PropertyValue propertyValue = { "Icon Image" }; XCTAssertEqual(rawLayer->getIconImage(), propertyValue, @"Setting iconImageName to a constant value should update icon-image."); - XCTAssertEqualObjects(layer.iconImageName, styleValue, + XCTAssertEqualObjects(layer.iconImageName, constantStyleValue, @"iconImageName should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconImageName = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconImageName = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, "Icon Image"}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getIconImage(), propertyValue, - @"Setting iconImageName to a function should update icon-image."); - XCTAssertEqualObjects(layer.iconImageName, styleValue, - @"iconImageName should round-trip functions."); + @"Setting iconImageName to a camera function should update icon-image."); + XCTAssertEqualObjects(layer.iconImageName, functionStyleValue, + @"iconImageName should round-trip camera functions."); + + layer.iconImageName = nil; XCTAssertTrue(rawLayer->getIconImage().isUndefined(), @"Unsetting iconImageName should return icon-image to the default value."); XCTAssertEqualObjects(layer.iconImageName, defaultStyleValue, @"iconImageName should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.iconImageName = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.iconImageName = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); } // icon-offset @@ -151,32 +169,55 @@ - (void)testProperties { @"icon-offset should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconOffset; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue: + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue: #if TARGET_OS_IPHONE [NSValue valueWithCGVector:CGVectorMake(1, 1)] #else [NSValue valueWithMGLVector:CGVectorMake(1, -1)] #endif ]; - layer.iconOffset = styleValue; - mbgl::style::PropertyValue> propertyValue = { { 1, 1 } }; + layer.iconOffset = constantStyleValue; + mbgl::style::DataDrivenPropertyValue> propertyValue = { { 1, 1 } }; XCTAssertEqual(rawLayer->getIconOffset(), propertyValue, @"Setting iconOffset to a constant value should update icon-offset."); - XCTAssertEqualObjects(layer.iconOffset, styleValue, + XCTAssertEqualObjects(layer.iconOffset, constantStyleValue, @"iconOffset should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconOffset = styleValue; - propertyValue = { mbgl::style::Function> { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconOffset = functionStyleValue; + + mbgl::style::IntervalStops> intervalStops = { {{18, { 1, 1 }}} }; + propertyValue = mbgl::style::CameraFunction> { 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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.iconOffset = functionStyleValue; + + mbgl::style::ExponentialStops> exponentialStops = { {{18, { 1, 1 }}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction> { "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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.iconOffset = functionStyleValue; + + mbgl::style::ExponentialStops> innerStops = { { {18, { 1, 1 }}}, 1.0 }; + std::map>> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction> { "keyName", compositeStops }; + XCTAssertEqual(rawLayer->getIconOffset(), propertyValue, - @"Setting iconOffset to a function should update icon-offset."); - XCTAssertEqualObjects(layer.iconOffset, styleValue, - @"iconOffset should round-trip functions."); + @"Setting iconOffset to a composite function should update icon-offset."); + XCTAssertEqualObjects(layer.iconOffset, functionStyleValue, + @"iconOffset should round-trip composite functions."); + layer.iconOffset = nil; XCTAssertTrue(rawLayer->getIconOffset().isUndefined(), @@ -191,32 +232,38 @@ - (void)testProperties { @"icon-optional should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconOptional; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@YES]; - layer.iconOptional = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@YES]; + layer.iconOptional = constantStyleValue; mbgl::style::PropertyValue propertyValue = { true }; XCTAssertEqual(rawLayer->getIconOptional(), propertyValue, @"Setting iconOptional to a constant value should update icon-optional."); - XCTAssertEqualObjects(layer.iconOptional, styleValue, + XCTAssertEqualObjects(layer.iconOptional, constantStyleValue, @"iconOptional should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconOptional = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconOptional = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, true}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getIconOptional(), propertyValue, - @"Setting iconOptional to a function should update icon-optional."); - XCTAssertEqualObjects(layer.iconOptional, styleValue, - @"iconOptional should round-trip functions."); + @"Setting iconOptional to a camera function should update icon-optional."); + XCTAssertEqualObjects(layer.iconOptional, functionStyleValue, + @"iconOptional should round-trip camera functions."); + + layer.iconOptional = nil; XCTAssertTrue(rawLayer->getIconOptional().isUndefined(), @"Unsetting iconOptional should return icon-optional to the default value."); XCTAssertEqualObjects(layer.iconOptional, defaultStyleValue, @"iconOptional should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // icon-padding @@ -225,26 +272,26 @@ - (void)testProperties { @"icon-padding should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconPadding; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.iconPadding = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.iconPadding = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getIconPadding(), propertyValue, @"Setting iconPadding to a constant value should update icon-padding."); - XCTAssertEqualObjects(layer.iconPadding, styleValue, + XCTAssertEqualObjects(layer.iconPadding, constantStyleValue, @"iconPadding should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconPadding = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconPadding = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getIconPadding(), propertyValue, - @"Setting iconPadding to a function should update icon-padding."); - XCTAssertEqualObjects(layer.iconPadding, styleValue, - @"iconPadding should round-trip functions."); + @"Setting iconPadding to a camera function should update icon-padding."); + XCTAssertEqualObjects(layer.iconPadding, functionStyleValue, + @"iconPadding should round-trip camera functions."); + + layer.iconPadding = nil; XCTAssertTrue(rawLayer->getIconPadding().isUndefined(), @@ -259,26 +306,49 @@ - (void)testProperties { @"icon-rotate should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconRotation; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.iconRotation = styleValue; - mbgl::style::PropertyValue propertyValue = { 0xff }; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.iconRotation = constantStyleValue; + mbgl::style::DataDrivenPropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getIconRotate(), propertyValue, @"Setting iconRotation to a constant value should update icon-rotate."); - XCTAssertEqualObjects(layer.iconRotation, styleValue, + XCTAssertEqualObjects(layer.iconRotation, constantStyleValue, @"iconRotation should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconRotation = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconRotation = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { 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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.iconRotation = functionStyleValue; + + mbgl::style::ExponentialStops exponentialStops = { {{18, 0xff}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction { "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."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.iconRotation = functionStyleValue; + + mbgl::style::ExponentialStops innerStops = { { {18, 0xff}}, 1.0 }; + std::map> compositeStops = { {10.0, innerStops} }; + + propertyValue = mbgl::style::CompositeFunction { "keyName", compositeStops }; + XCTAssertEqual(rawLayer->getIconRotate(), propertyValue, - @"Setting iconRotation to a function should update icon-rotate."); - XCTAssertEqualObjects(layer.iconRotation, styleValue, - @"iconRotation should round-trip functions."); + @"Setting iconRotation to a composite function should update icon-rotate."); + XCTAssertEqualObjects(layer.iconRotation, functionStyleValue, + @"iconRotation should round-trip composite functions."); + layer.iconRotation = nil; XCTAssertTrue(rawLayer->getIconRotate().isUndefined(), @@ -293,32 +363,38 @@ - (void)testProperties { @"icon-rotation-alignment should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconRotationAlignment; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentAuto]]; - layer.iconRotationAlignment = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentAuto]]; + layer.iconRotationAlignment = constantStyleValue; mbgl::style::PropertyValue propertyValue = { mbgl::style::AlignmentType::Auto }; XCTAssertEqual(rawLayer->getIconRotationAlignment(), propertyValue, @"Setting iconRotationAlignment to a constant value should update icon-rotation-alignment."); - XCTAssertEqualObjects(layer.iconRotationAlignment, styleValue, + XCTAssertEqualObjects(layer.iconRotationAlignment, constantStyleValue, @"iconRotationAlignment should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconRotationAlignment = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconRotationAlignment = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::AlignmentType::Auto}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getIconRotationAlignment(), propertyValue, - @"Setting iconRotationAlignment to a function should update icon-rotation-alignment."); - XCTAssertEqualObjects(layer.iconRotationAlignment, styleValue, - @"iconRotationAlignment should round-trip functions."); + @"Setting iconRotationAlignment to a camera function should update icon-rotation-alignment."); + XCTAssertEqualObjects(layer.iconRotationAlignment, functionStyleValue, + @"iconRotationAlignment should round-trip camera functions."); + + layer.iconRotationAlignment = nil; XCTAssertTrue(rawLayer->getIconRotationAlignment().isUndefined(), @"Unsetting iconRotationAlignment should return icon-rotation-alignment to the default value."); XCTAssertEqualObjects(layer.iconRotationAlignment, defaultStyleValue, @"iconRotationAlignment should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // icon-size @@ -327,26 +403,26 @@ - (void)testProperties { @"icon-size should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconScale; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.iconScale = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.iconScale = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getIconSize(), propertyValue, @"Setting iconScale to a constant value should update icon-size."); - XCTAssertEqualObjects(layer.iconScale, styleValue, + XCTAssertEqualObjects(layer.iconScale, constantStyleValue, @"iconScale should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconScale = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconScale = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getIconSize(), propertyValue, - @"Setting iconScale to a function should update icon-size."); - XCTAssertEqualObjects(layer.iconScale, styleValue, - @"iconScale should round-trip functions."); + @"Setting iconScale to a camera function should update icon-size."); + XCTAssertEqualObjects(layer.iconScale, functionStyleValue, + @"iconScale should round-trip camera functions."); + + layer.iconScale = nil; XCTAssertTrue(rawLayer->getIconSize().isUndefined(), @@ -361,32 +437,38 @@ - (void)testProperties { @"icon-text-fit should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconTextFit; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLIconTextFit:MGLIconTextFitBoth]]; - layer.iconTextFit = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLIconTextFit:MGLIconTextFitBoth]]; + layer.iconTextFit = constantStyleValue; mbgl::style::PropertyValue propertyValue = { mbgl::style::IconTextFitType::Both }; XCTAssertEqual(rawLayer->getIconTextFit(), propertyValue, @"Setting iconTextFit to a constant value should update icon-text-fit."); - XCTAssertEqualObjects(layer.iconTextFit, styleValue, + XCTAssertEqualObjects(layer.iconTextFit, constantStyleValue, @"iconTextFit should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconTextFit = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconTextFit = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::IconTextFitType::Both}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getIconTextFit(), propertyValue, - @"Setting iconTextFit to a function should update icon-text-fit."); - XCTAssertEqualObjects(layer.iconTextFit, styleValue, - @"iconTextFit should round-trip functions."); + @"Setting iconTextFit to a camera function should update icon-text-fit."); + XCTAssertEqualObjects(layer.iconTextFit, functionStyleValue, + @"iconTextFit should round-trip camera functions."); + + layer.iconTextFit = nil; XCTAssertTrue(rawLayer->getIconTextFit().isUndefined(), @"Unsetting iconTextFit should return icon-text-fit to the default value."); XCTAssertEqualObjects(layer.iconTextFit, defaultStyleValue, @"iconTextFit should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // icon-text-fit-padding @@ -395,32 +477,32 @@ - (void)testProperties { @"icon-text-fit-padding should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconTextFitPadding; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue: + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue: #if TARGET_OS_IPHONE [NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(1, 1, 1, 1)] #else [NSValue valueWithEdgeInsets:NSEdgeInsetsMake(1, 1, 1, 1)] #endif ]; - layer.iconTextFitPadding = styleValue; + layer.iconTextFitPadding = constantStyleValue; mbgl::style::PropertyValue> propertyValue = { { 1, 1, 1, 1 } }; XCTAssertEqual(rawLayer->getIconTextFitPadding(), propertyValue, @"Setting iconTextFitPadding to a constant value should update icon-text-fit-padding."); - XCTAssertEqualObjects(layer.iconTextFitPadding, styleValue, + XCTAssertEqualObjects(layer.iconTextFitPadding, constantStyleValue, @"iconTextFitPadding should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconTextFitPadding = styleValue; - propertyValue = { mbgl::style::Function> { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconTextFitPadding = functionStyleValue; + + mbgl::style::IntervalStops> intervalStops = { {{18, { 1, 1, 1, 1 }}} }; + propertyValue = mbgl::style::CameraFunction> { intervalStops }; + XCTAssertEqual(rawLayer->getIconTextFitPadding(), propertyValue, - @"Setting iconTextFitPadding to a function should update icon-text-fit-padding."); - XCTAssertEqualObjects(layer.iconTextFitPadding, styleValue, - @"iconTextFitPadding should round-trip functions."); + @"Setting iconTextFitPadding to a camera function should update icon-text-fit-padding."); + XCTAssertEqualObjects(layer.iconTextFitPadding, functionStyleValue, + @"iconTextFitPadding should round-trip camera functions."); + + layer.iconTextFitPadding = nil; XCTAssertTrue(rawLayer->getIconTextFitPadding().isUndefined(), @@ -435,32 +517,38 @@ - (void)testProperties { @"icon-keep-upright should be unset initially."); MGLStyleValue *defaultStyleValue = layer.keepsIconUpright; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@YES]; - layer.keepsIconUpright = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@YES]; + layer.keepsIconUpright = constantStyleValue; mbgl::style::PropertyValue propertyValue = { true }; XCTAssertEqual(rawLayer->getIconKeepUpright(), propertyValue, @"Setting keepsIconUpright to a constant value should update icon-keep-upright."); - XCTAssertEqualObjects(layer.keepsIconUpright, styleValue, + XCTAssertEqualObjects(layer.keepsIconUpright, constantStyleValue, @"keepsIconUpright should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.keepsIconUpright = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.keepsIconUpright = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, true}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getIconKeepUpright(), propertyValue, - @"Setting keepsIconUpright to a function should update icon-keep-upright."); - XCTAssertEqualObjects(layer.keepsIconUpright, styleValue, - @"keepsIconUpright should round-trip functions."); + @"Setting keepsIconUpright to a camera function should update icon-keep-upright."); + XCTAssertEqualObjects(layer.keepsIconUpright, functionStyleValue, + @"keepsIconUpright should round-trip camera functions."); + + layer.keepsIconUpright = nil; XCTAssertTrue(rawLayer->getIconKeepUpright().isUndefined(), @"Unsetting keepsIconUpright should return icon-keep-upright to the default value."); XCTAssertEqualObjects(layer.keepsIconUpright, defaultStyleValue, @"keepsIconUpright should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // text-keep-upright @@ -469,32 +557,38 @@ - (void)testProperties { @"text-keep-upright should be unset initially."); MGLStyleValue *defaultStyleValue = layer.keepsTextUpright; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@NO]; - layer.keepsTextUpright = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@NO]; + layer.keepsTextUpright = constantStyleValue; mbgl::style::PropertyValue propertyValue = { false }; XCTAssertEqual(rawLayer->getTextKeepUpright(), propertyValue, @"Setting keepsTextUpright to a constant value should update text-keep-upright."); - XCTAssertEqualObjects(layer.keepsTextUpright, styleValue, + XCTAssertEqualObjects(layer.keepsTextUpright, constantStyleValue, @"keepsTextUpright should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.keepsTextUpright = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.keepsTextUpright = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, false}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextKeepUpright(), propertyValue, - @"Setting keepsTextUpright to a function should update text-keep-upright."); - XCTAssertEqualObjects(layer.keepsTextUpright, styleValue, - @"keepsTextUpright should round-trip functions."); + @"Setting keepsTextUpright to a camera function should update text-keep-upright."); + XCTAssertEqualObjects(layer.keepsTextUpright, functionStyleValue, + @"keepsTextUpright should round-trip camera functions."); + + layer.keepsTextUpright = nil; XCTAssertTrue(rawLayer->getTextKeepUpright().isUndefined(), @"Unsetting keepsTextUpright should return text-keep-upright to the default value."); XCTAssertEqualObjects(layer.keepsTextUpright, defaultStyleValue, @"keepsTextUpright should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // text-max-angle @@ -503,26 +597,26 @@ - (void)testProperties { @"text-max-angle should be unset initially."); MGLStyleValue *defaultStyleValue = layer.maximumTextAngle; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.maximumTextAngle = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.maximumTextAngle = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getTextMaxAngle(), propertyValue, @"Setting maximumTextAngle to a constant value should update text-max-angle."); - XCTAssertEqualObjects(layer.maximumTextAngle, styleValue, + XCTAssertEqualObjects(layer.maximumTextAngle, constantStyleValue, @"maximumTextAngle should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.maximumTextAngle = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.maximumTextAngle = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextMaxAngle(), propertyValue, - @"Setting maximumTextAngle to a function should update text-max-angle."); - XCTAssertEqualObjects(layer.maximumTextAngle, styleValue, - @"maximumTextAngle should round-trip functions."); + @"Setting maximumTextAngle to a camera function should update text-max-angle."); + XCTAssertEqualObjects(layer.maximumTextAngle, functionStyleValue, + @"maximumTextAngle should round-trip camera functions."); + + layer.maximumTextAngle = nil; XCTAssertTrue(rawLayer->getTextMaxAngle().isUndefined(), @@ -537,26 +631,26 @@ - (void)testProperties { @"text-max-width should be unset initially."); MGLStyleValue *defaultStyleValue = layer.maximumTextWidth; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.maximumTextWidth = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.maximumTextWidth = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue, @"Setting maximumTextWidth to a constant value should update text-max-width."); - XCTAssertEqualObjects(layer.maximumTextWidth, styleValue, + XCTAssertEqualObjects(layer.maximumTextWidth, constantStyleValue, @"maximumTextWidth should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.maximumTextWidth = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.maximumTextWidth = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue, - @"Setting maximumTextWidth to a function should update text-max-width."); - XCTAssertEqualObjects(layer.maximumTextWidth, styleValue, - @"maximumTextWidth should round-trip functions."); + @"Setting maximumTextWidth to a camera function should update text-max-width."); + XCTAssertEqualObjects(layer.maximumTextWidth, functionStyleValue, + @"maximumTextWidth should round-trip camera functions."); + + layer.maximumTextWidth = nil; XCTAssertTrue(rawLayer->getTextMaxWidth().isUndefined(), @@ -571,32 +665,38 @@ - (void)testProperties { @"symbol-avoid-edges should be unset initially."); MGLStyleValue *defaultStyleValue = layer.symbolAvoidsEdges; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@YES]; - layer.symbolAvoidsEdges = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@YES]; + layer.symbolAvoidsEdges = constantStyleValue; mbgl::style::PropertyValue propertyValue = { true }; XCTAssertEqual(rawLayer->getSymbolAvoidEdges(), propertyValue, @"Setting symbolAvoidsEdges to a constant value should update symbol-avoid-edges."); - XCTAssertEqualObjects(layer.symbolAvoidsEdges, styleValue, + XCTAssertEqualObjects(layer.symbolAvoidsEdges, constantStyleValue, @"symbolAvoidsEdges should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.symbolAvoidsEdges = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.symbolAvoidsEdges = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, true}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getSymbolAvoidEdges(), propertyValue, - @"Setting symbolAvoidsEdges to a function should update symbol-avoid-edges."); - XCTAssertEqualObjects(layer.symbolAvoidsEdges, styleValue, - @"symbolAvoidsEdges should round-trip functions."); + @"Setting symbolAvoidsEdges to a camera function should update symbol-avoid-edges."); + XCTAssertEqualObjects(layer.symbolAvoidsEdges, functionStyleValue, + @"symbolAvoidsEdges should round-trip camera functions."); + + layer.symbolAvoidsEdges = nil; XCTAssertTrue(rawLayer->getSymbolAvoidEdges().isUndefined(), @"Unsetting symbolAvoidsEdges should return symbol-avoid-edges to the default value."); XCTAssertEqualObjects(layer.symbolAvoidsEdges, defaultStyleValue, @"symbolAvoidsEdges should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // symbol-placement @@ -605,32 +705,38 @@ - (void)testProperties { @"symbol-placement should be unset initially."); MGLStyleValue *defaultStyleValue = layer.symbolPlacement; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLSymbolPlacement:MGLSymbolPlacementLine]]; - layer.symbolPlacement = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLSymbolPlacement:MGLSymbolPlacementLine]]; + layer.symbolPlacement = constantStyleValue; mbgl::style::PropertyValue propertyValue = { mbgl::style::SymbolPlacementType::Line }; XCTAssertEqual(rawLayer->getSymbolPlacement(), propertyValue, @"Setting symbolPlacement to a constant value should update symbol-placement."); - XCTAssertEqualObjects(layer.symbolPlacement, styleValue, + XCTAssertEqualObjects(layer.symbolPlacement, constantStyleValue, @"symbolPlacement should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.symbolPlacement = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.symbolPlacement = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::SymbolPlacementType::Line}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getSymbolPlacement(), propertyValue, - @"Setting symbolPlacement to a function should update symbol-placement."); - XCTAssertEqualObjects(layer.symbolPlacement, styleValue, - @"symbolPlacement should round-trip functions."); + @"Setting symbolPlacement to a camera function should update symbol-placement."); + XCTAssertEqualObjects(layer.symbolPlacement, functionStyleValue, + @"symbolPlacement should round-trip camera functions."); + + layer.symbolPlacement = nil; XCTAssertTrue(rawLayer->getSymbolPlacement().isUndefined(), @"Unsetting symbolPlacement should return symbol-placement to the default value."); XCTAssertEqualObjects(layer.symbolPlacement, defaultStyleValue, @"symbolPlacement should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // symbol-spacing @@ -639,26 +745,26 @@ - (void)testProperties { @"symbol-spacing should be unset initially."); MGLStyleValue *defaultStyleValue = layer.symbolSpacing; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.symbolSpacing = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.symbolSpacing = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getSymbolSpacing(), propertyValue, @"Setting symbolSpacing to a constant value should update symbol-spacing."); - XCTAssertEqualObjects(layer.symbolSpacing, styleValue, + XCTAssertEqualObjects(layer.symbolSpacing, constantStyleValue, @"symbolSpacing should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.symbolSpacing = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.symbolSpacing = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getSymbolSpacing(), propertyValue, - @"Setting symbolSpacing to a function should update symbol-spacing."); - XCTAssertEqualObjects(layer.symbolSpacing, styleValue, - @"symbolSpacing should round-trip functions."); + @"Setting symbolSpacing to a camera function should update symbol-spacing."); + XCTAssertEqualObjects(layer.symbolSpacing, functionStyleValue, + @"symbolSpacing should round-trip camera functions."); + + layer.symbolSpacing = nil; XCTAssertTrue(rawLayer->getSymbolSpacing().isUndefined(), @@ -673,32 +779,38 @@ - (void)testProperties { @"text-field should be unset initially."); MGLStyleValue *defaultStyleValue = layer.text; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@"Text Field"]; - layer.text = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@"Text Field"]; + layer.text = constantStyleValue; mbgl::style::PropertyValue propertyValue = { "Text Field" }; XCTAssertEqual(rawLayer->getTextField(), propertyValue, @"Setting text to a constant value should update text-field."); - XCTAssertEqualObjects(layer.text, styleValue, + XCTAssertEqualObjects(layer.text, constantStyleValue, @"text should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.text = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.text = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, "Text Field"}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextField(), propertyValue, - @"Setting text to a function should update text-field."); - XCTAssertEqualObjects(layer.text, styleValue, - @"text should round-trip functions."); + @"Setting text to a camera function should update text-field."); + XCTAssertEqualObjects(layer.text, functionStyleValue, + @"text should round-trip camera functions."); + + layer.text = nil; XCTAssertTrue(rawLayer->getTextField().isUndefined(), @"Unsetting text should return text-field to the default value."); XCTAssertEqualObjects(layer.text, defaultStyleValue, @"text should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.text = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.text = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); } // text-allow-overlap @@ -707,32 +819,38 @@ - (void)testProperties { @"text-allow-overlap should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textAllowsOverlap; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@YES]; - layer.textAllowsOverlap = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@YES]; + layer.textAllowsOverlap = constantStyleValue; mbgl::style::PropertyValue propertyValue = { true }; XCTAssertEqual(rawLayer->getTextAllowOverlap(), propertyValue, @"Setting textAllowsOverlap to a constant value should update text-allow-overlap."); - XCTAssertEqualObjects(layer.textAllowsOverlap, styleValue, + XCTAssertEqualObjects(layer.textAllowsOverlap, constantStyleValue, @"textAllowsOverlap should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textAllowsOverlap = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textAllowsOverlap = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, true}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextAllowOverlap(), propertyValue, - @"Setting textAllowsOverlap to a function should update text-allow-overlap."); - XCTAssertEqualObjects(layer.textAllowsOverlap, styleValue, - @"textAllowsOverlap should round-trip functions."); + @"Setting textAllowsOverlap to a camera function should update text-allow-overlap."); + XCTAssertEqualObjects(layer.textAllowsOverlap, functionStyleValue, + @"textAllowsOverlap should round-trip camera functions."); + + layer.textAllowsOverlap = nil; XCTAssertTrue(rawLayer->getTextAllowOverlap().isUndefined(), @"Unsetting textAllowsOverlap should return text-allow-overlap to the default value."); XCTAssertEqualObjects(layer.textAllowsOverlap, defaultStyleValue, @"textAllowsOverlap should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // text-anchor @@ -741,32 +859,38 @@ - (void)testProperties { @"text-anchor should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textAnchor; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomRight]]; - layer.textAnchor = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomRight]]; + layer.textAnchor = constantStyleValue; mbgl::style::PropertyValue propertyValue = { mbgl::style::TextAnchorType::BottomRight }; XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue, @"Setting textAnchor to a constant value should update text-anchor."); - XCTAssertEqualObjects(layer.textAnchor, styleValue, + XCTAssertEqualObjects(layer.textAnchor, constantStyleValue, @"textAnchor should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textAnchor = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textAnchor = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::TextAnchorType::BottomRight}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue, - @"Setting textAnchor to a function should update text-anchor."); - XCTAssertEqualObjects(layer.textAnchor, styleValue, - @"textAnchor should round-trip functions."); + @"Setting textAnchor to a camera function should update text-anchor."); + XCTAssertEqualObjects(layer.textAnchor, functionStyleValue, + @"textAnchor should round-trip camera functions."); + + layer.textAnchor = nil; XCTAssertTrue(rawLayer->getTextAnchor().isUndefined(), @"Unsetting textAnchor should return text-anchor to the default value."); XCTAssertEqualObjects(layer.textAnchor, defaultStyleValue, @"textAnchor should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.textAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.textAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); } // text-font @@ -775,32 +899,38 @@ - (void)testProperties { @"text-font should be unset initially."); MGLStyleValue *> *defaultStyleValue = layer.textFontNames; - MGLStyleValue *> *styleValue = [MGLStyleValue *> valueWithRawValue:@[@"Text Font", @"Tnof Txet"]]; - layer.textFontNames = styleValue; + MGLStyleValue *> *constantStyleValue = [MGLStyleValue *> valueWithRawValue:@[@"Text Font", @"Tnof Txet"]]; + layer.textFontNames = constantStyleValue; mbgl::style::PropertyValue> propertyValue = { { "Text Font", "Tnof Txet" } }; XCTAssertEqual(rawLayer->getTextFont(), propertyValue, @"Setting textFontNames to a constant value should update text-font."); - XCTAssertEqualObjects(layer.textFontNames, styleValue, + XCTAssertEqualObjects(layer.textFontNames, constantStyleValue, @"textFontNames should round-trip constant values."); - styleValue = [MGLStyleValue *> valueWithStops:@{ - @18: styleValue, - }]; - layer.textFontNames = styleValue; - propertyValue = { mbgl::style::Function> { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue *> * functionStyleValue = [MGLStyleValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textFontNames = functionStyleValue; + + mbgl::style::IntervalStops> intervalStops = { {{18, { "Text Font", "Tnof Txet" }}} }; + propertyValue = mbgl::style::CameraFunction> { intervalStops }; + XCTAssertEqual(rawLayer->getTextFont(), propertyValue, - @"Setting textFontNames to a function should update text-font."); - XCTAssertEqualObjects(layer.textFontNames, styleValue, - @"textFontNames should round-trip functions."); + @"Setting textFontNames to a camera function should update text-font."); + XCTAssertEqualObjects(layer.textFontNames, functionStyleValue, + @"textFontNames should round-trip camera functions."); + + layer.textFontNames = nil; XCTAssertTrue(rawLayer->getTextFont().isUndefined(), @"Unsetting textFontNames should return text-font to the default value."); XCTAssertEqualObjects(layer.textFontNames, defaultStyleValue, @"textFontNames should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue *> 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 *> 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 @@ -809,26 +939,26 @@ - (void)testProperties { @"text-size should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textFontSize; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.textFontSize = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.textFontSize = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getTextSize(), propertyValue, @"Setting textFontSize to a constant value should update text-size."); - XCTAssertEqualObjects(layer.textFontSize, styleValue, + XCTAssertEqualObjects(layer.textFontSize, constantStyleValue, @"textFontSize should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textFontSize = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textFontSize = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextSize(), propertyValue, - @"Setting textFontSize to a function should update text-size."); - XCTAssertEqualObjects(layer.textFontSize, styleValue, - @"textFontSize should round-trip functions."); + @"Setting textFontSize to a camera function should update text-size."); + XCTAssertEqualObjects(layer.textFontSize, functionStyleValue, + @"textFontSize should round-trip camera functions."); + + layer.textFontSize = nil; XCTAssertTrue(rawLayer->getTextSize().isUndefined(), @@ -843,32 +973,38 @@ - (void)testProperties { @"text-ignore-placement should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textIgnoresPlacement; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@YES]; - layer.textIgnoresPlacement = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@YES]; + layer.textIgnoresPlacement = constantStyleValue; mbgl::style::PropertyValue propertyValue = { true }; XCTAssertEqual(rawLayer->getTextIgnorePlacement(), propertyValue, @"Setting textIgnoresPlacement to a constant value should update text-ignore-placement."); - XCTAssertEqualObjects(layer.textIgnoresPlacement, styleValue, + XCTAssertEqualObjects(layer.textIgnoresPlacement, constantStyleValue, @"textIgnoresPlacement should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textIgnoresPlacement = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textIgnoresPlacement = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, true}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextIgnorePlacement(), propertyValue, - @"Setting textIgnoresPlacement to a function should update text-ignore-placement."); - XCTAssertEqualObjects(layer.textIgnoresPlacement, styleValue, - @"textIgnoresPlacement should round-trip functions."); + @"Setting textIgnoresPlacement to a camera function should update text-ignore-placement."); + XCTAssertEqualObjects(layer.textIgnoresPlacement, functionStyleValue, + @"textIgnoresPlacement should round-trip camera functions."); + + layer.textIgnoresPlacement = nil; XCTAssertTrue(rawLayer->getTextIgnorePlacement().isUndefined(), @"Unsetting textIgnoresPlacement should return text-ignore-placement to the default value."); XCTAssertEqualObjects(layer.textIgnoresPlacement, defaultStyleValue, @"textIgnoresPlacement should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // text-justify @@ -877,32 +1013,38 @@ - (void)testProperties { @"text-justify should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textJustification; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLTextJustification:MGLTextJustificationRight]]; - layer.textJustification = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLTextJustification:MGLTextJustificationRight]]; + layer.textJustification = constantStyleValue; mbgl::style::PropertyValue propertyValue = { mbgl::style::TextJustifyType::Right }; XCTAssertEqual(rawLayer->getTextJustify(), propertyValue, @"Setting textJustification to a constant value should update text-justify."); - XCTAssertEqualObjects(layer.textJustification, styleValue, + XCTAssertEqualObjects(layer.textJustification, constantStyleValue, @"textJustification should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textJustification = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textJustification = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::TextJustifyType::Right}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextJustify(), propertyValue, - @"Setting textJustification to a function should update text-justify."); - XCTAssertEqualObjects(layer.textJustification, styleValue, - @"textJustification should round-trip functions."); + @"Setting textJustification to a camera function should update text-justify."); + XCTAssertEqualObjects(layer.textJustification, functionStyleValue, + @"textJustification should round-trip camera functions."); + + layer.textJustification = nil; XCTAssertTrue(rawLayer->getTextJustify().isUndefined(), @"Unsetting textJustification should return text-justify to the default value."); XCTAssertEqualObjects(layer.textJustification, defaultStyleValue, @"textJustification should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.textJustification = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.textJustification = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); } // text-letter-spacing @@ -911,26 +1053,26 @@ - (void)testProperties { @"text-letter-spacing should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textLetterSpacing; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.textLetterSpacing = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.textLetterSpacing = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue, @"Setting textLetterSpacing to a constant value should update text-letter-spacing."); - XCTAssertEqualObjects(layer.textLetterSpacing, styleValue, + XCTAssertEqualObjects(layer.textLetterSpacing, constantStyleValue, @"textLetterSpacing should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textLetterSpacing = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textLetterSpacing = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue, - @"Setting textLetterSpacing to a function should update text-letter-spacing."); - XCTAssertEqualObjects(layer.textLetterSpacing, styleValue, - @"textLetterSpacing should round-trip functions."); + @"Setting textLetterSpacing to a camera function should update text-letter-spacing."); + XCTAssertEqualObjects(layer.textLetterSpacing, functionStyleValue, + @"textLetterSpacing should round-trip camera functions."); + + layer.textLetterSpacing = nil; XCTAssertTrue(rawLayer->getTextLetterSpacing().isUndefined(), @@ -945,26 +1087,26 @@ - (void)testProperties { @"text-line-height should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textLineHeight; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.textLineHeight = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.textLineHeight = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getTextLineHeight(), propertyValue, @"Setting textLineHeight to a constant value should update text-line-height."); - XCTAssertEqualObjects(layer.textLineHeight, styleValue, + XCTAssertEqualObjects(layer.textLineHeight, constantStyleValue, @"textLineHeight should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textLineHeight = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textLineHeight = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextLineHeight(), propertyValue, - @"Setting textLineHeight to a function should update text-line-height."); - XCTAssertEqualObjects(layer.textLineHeight, styleValue, - @"textLineHeight should round-trip functions."); + @"Setting textLineHeight to a camera function should update text-line-height."); + XCTAssertEqualObjects(layer.textLineHeight, functionStyleValue, + @"textLineHeight should round-trip camera functions."); + + layer.textLineHeight = nil; XCTAssertTrue(rawLayer->getTextLineHeight().isUndefined(), @@ -979,32 +1121,32 @@ - (void)testProperties { @"text-offset should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textOffset; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue: + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue: #if TARGET_OS_IPHONE [NSValue valueWithCGVector:CGVectorMake(1, 1)] #else [NSValue valueWithMGLVector:CGVectorMake(1, -1)] #endif ]; - layer.textOffset = styleValue; + layer.textOffset = constantStyleValue; mbgl::style::PropertyValue> propertyValue = { { 1, 1 } }; XCTAssertEqual(rawLayer->getTextOffset(), propertyValue, @"Setting textOffset to a constant value should update text-offset."); - XCTAssertEqualObjects(layer.textOffset, styleValue, + XCTAssertEqualObjects(layer.textOffset, constantStyleValue, @"textOffset should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textOffset = styleValue; - propertyValue = { mbgl::style::Function> { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textOffset = functionStyleValue; + + mbgl::style::IntervalStops> intervalStops = { {{18, { 1, 1 }}} }; + propertyValue = mbgl::style::CameraFunction> { intervalStops }; + XCTAssertEqual(rawLayer->getTextOffset(), propertyValue, - @"Setting textOffset to a function should update text-offset."); - XCTAssertEqualObjects(layer.textOffset, styleValue, - @"textOffset should round-trip functions."); + @"Setting textOffset to a camera function should update text-offset."); + XCTAssertEqualObjects(layer.textOffset, functionStyleValue, + @"textOffset should round-trip camera functions."); + + layer.textOffset = nil; XCTAssertTrue(rawLayer->getTextOffset().isUndefined(), @@ -1019,32 +1161,38 @@ - (void)testProperties { @"text-optional should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textOptional; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@YES]; - layer.textOptional = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@YES]; + layer.textOptional = constantStyleValue; mbgl::style::PropertyValue propertyValue = { true }; XCTAssertEqual(rawLayer->getTextOptional(), propertyValue, @"Setting textOptional to a constant value should update text-optional."); - XCTAssertEqualObjects(layer.textOptional, styleValue, + XCTAssertEqualObjects(layer.textOptional, constantStyleValue, @"textOptional should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textOptional = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textOptional = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, true}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextOptional(), propertyValue, - @"Setting textOptional to a function should update text-optional."); - XCTAssertEqualObjects(layer.textOptional, styleValue, - @"textOptional should round-trip functions."); + @"Setting textOptional to a camera function should update text-optional."); + XCTAssertEqualObjects(layer.textOptional, functionStyleValue, + @"textOptional should round-trip camera functions."); + + layer.textOptional = nil; XCTAssertTrue(rawLayer->getTextOptional().isUndefined(), @"Unsetting textOptional should return text-optional to the default value."); XCTAssertEqualObjects(layer.textOptional, defaultStyleValue, @"textOptional should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // text-padding @@ -1053,26 +1201,26 @@ - (void)testProperties { @"text-padding should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textPadding; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.textPadding = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.textPadding = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getTextPadding(), propertyValue, @"Setting textPadding to a constant value should update text-padding."); - XCTAssertEqualObjects(layer.textPadding, styleValue, + XCTAssertEqualObjects(layer.textPadding, constantStyleValue, @"textPadding should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textPadding = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textPadding = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextPadding(), propertyValue, - @"Setting textPadding to a function should update text-padding."); - XCTAssertEqualObjects(layer.textPadding, styleValue, - @"textPadding should round-trip functions."); + @"Setting textPadding to a camera function should update text-padding."); + XCTAssertEqualObjects(layer.textPadding, functionStyleValue, + @"textPadding should round-trip camera functions."); + + layer.textPadding = nil; XCTAssertTrue(rawLayer->getTextPadding().isUndefined(), @@ -1087,32 +1235,38 @@ - (void)testProperties { @"text-pitch-alignment should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textPitchAlignment; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLTextPitchAlignment:MGLTextPitchAlignmentAuto]]; - layer.textPitchAlignment = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLTextPitchAlignment:MGLTextPitchAlignmentAuto]]; + layer.textPitchAlignment = constantStyleValue; mbgl::style::PropertyValue propertyValue = { mbgl::style::AlignmentType::Auto }; XCTAssertEqual(rawLayer->getTextPitchAlignment(), propertyValue, @"Setting textPitchAlignment to a constant value should update text-pitch-alignment."); - XCTAssertEqualObjects(layer.textPitchAlignment, styleValue, + XCTAssertEqualObjects(layer.textPitchAlignment, constantStyleValue, @"textPitchAlignment should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textPitchAlignment = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textPitchAlignment = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::AlignmentType::Auto}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextPitchAlignment(), propertyValue, - @"Setting textPitchAlignment to a function should update text-pitch-alignment."); - XCTAssertEqualObjects(layer.textPitchAlignment, styleValue, - @"textPitchAlignment should round-trip functions."); + @"Setting textPitchAlignment to a camera function should update text-pitch-alignment."); + XCTAssertEqualObjects(layer.textPitchAlignment, functionStyleValue, + @"textPitchAlignment should round-trip camera functions."); + + layer.textPitchAlignment = nil; XCTAssertTrue(rawLayer->getTextPitchAlignment().isUndefined(), @"Unsetting textPitchAlignment should return text-pitch-alignment to the default value."); XCTAssertEqualObjects(layer.textPitchAlignment, defaultStyleValue, @"textPitchAlignment should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // text-rotate @@ -1121,26 +1275,26 @@ - (void)testProperties { @"text-rotate should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textRotation; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.textRotation = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.textRotation = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getTextRotate(), propertyValue, @"Setting textRotation to a constant value should update text-rotate."); - XCTAssertEqualObjects(layer.textRotation, styleValue, + XCTAssertEqualObjects(layer.textRotation, constantStyleValue, @"textRotation should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textRotation = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textRotation = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextRotate(), propertyValue, - @"Setting textRotation to a function should update text-rotate."); - XCTAssertEqualObjects(layer.textRotation, styleValue, - @"textRotation should round-trip functions."); + @"Setting textRotation to a camera function should update text-rotate."); + XCTAssertEqualObjects(layer.textRotation, functionStyleValue, + @"textRotation should round-trip camera functions."); + + layer.textRotation = nil; XCTAssertTrue(rawLayer->getTextRotate().isUndefined(), @@ -1155,32 +1309,38 @@ - (void)testProperties { @"text-rotation-alignment should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textRotationAlignment; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLTextRotationAlignment:MGLTextRotationAlignmentAuto]]; - layer.textRotationAlignment = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLTextRotationAlignment:MGLTextRotationAlignmentAuto]]; + layer.textRotationAlignment = constantStyleValue; mbgl::style::PropertyValue propertyValue = { mbgl::style::AlignmentType::Auto }; XCTAssertEqual(rawLayer->getTextRotationAlignment(), propertyValue, @"Setting textRotationAlignment to a constant value should update text-rotation-alignment."); - XCTAssertEqualObjects(layer.textRotationAlignment, styleValue, + XCTAssertEqualObjects(layer.textRotationAlignment, constantStyleValue, @"textRotationAlignment should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textRotationAlignment = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textRotationAlignment = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::AlignmentType::Auto}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextRotationAlignment(), propertyValue, - @"Setting textRotationAlignment to a function should update text-rotation-alignment."); - XCTAssertEqualObjects(layer.textRotationAlignment, styleValue, - @"textRotationAlignment should round-trip functions."); + @"Setting textRotationAlignment to a camera function should update text-rotation-alignment."); + XCTAssertEqualObjects(layer.textRotationAlignment, functionStyleValue, + @"textRotationAlignment should round-trip camera functions."); + + layer.textRotationAlignment = nil; XCTAssertTrue(rawLayer->getTextRotationAlignment().isUndefined(), @"Unsetting textRotationAlignment should return text-rotation-alignment to the default value."); XCTAssertEqualObjects(layer.textRotationAlignment, defaultStyleValue, @"textRotationAlignment should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // text-transform @@ -1189,32 +1349,38 @@ - (void)testProperties { @"text-transform should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textTransform; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLTextTransform:MGLTextTransformLowercase]]; - layer.textTransform = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLTextTransform:MGLTextTransformLowercase]]; + layer.textTransform = constantStyleValue; mbgl::style::PropertyValue propertyValue = { mbgl::style::TextTransformType::Lowercase }; XCTAssertEqual(rawLayer->getTextTransform(), propertyValue, @"Setting textTransform to a constant value should update text-transform."); - XCTAssertEqualObjects(layer.textTransform, styleValue, + XCTAssertEqualObjects(layer.textTransform, constantStyleValue, @"textTransform should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textTransform = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textTransform = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::TextTransformType::Lowercase}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextTransform(), propertyValue, - @"Setting textTransform to a function should update text-transform."); - XCTAssertEqualObjects(layer.textTransform, styleValue, - @"textTransform should round-trip functions."); + @"Setting textTransform to a camera function should update text-transform."); + XCTAssertEqualObjects(layer.textTransform, functionStyleValue, + @"textTransform should round-trip camera functions."); + + layer.textTransform = nil; XCTAssertTrue(rawLayer->getTextTransform().isUndefined(), @"Unsetting textTransform should return text-transform to the default value."); XCTAssertEqualObjects(layer.textTransform, defaultStyleValue, @"textTransform should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.textTransform = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); + + functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.textTransform = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); } // icon-color @@ -1223,26 +1389,26 @@ - (void)testProperties { @"icon-color should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconColor; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; - layer.iconColor = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; + layer.iconColor = constantStyleValue; mbgl::style::PropertyValue propertyValue = { { 1, 0, 0, 1 } }; XCTAssertEqual(rawLayer->getIconColor(), propertyValue, @"Setting iconColor to a constant value should update icon-color."); - XCTAssertEqualObjects(layer.iconColor, styleValue, + XCTAssertEqualObjects(layer.iconColor, constantStyleValue, @"iconColor should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconColor = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconColor = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, { 1, 0, 0, 1 }}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getIconColor(), propertyValue, - @"Setting iconColor to a function should update icon-color."); - XCTAssertEqualObjects(layer.iconColor, styleValue, - @"iconColor should round-trip functions."); + @"Setting iconColor to a camera function should update icon-color."); + XCTAssertEqualObjects(layer.iconColor, functionStyleValue, + @"iconColor should round-trip camera functions."); + + layer.iconColor = nil; XCTAssertTrue(rawLayer->getIconColor().isUndefined(), @@ -1257,26 +1423,26 @@ - (void)testProperties { @"icon-halo-blur should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconHaloBlur; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.iconHaloBlur = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.iconHaloBlur = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue, @"Setting iconHaloBlur to a constant value should update icon-halo-blur."); - XCTAssertEqualObjects(layer.iconHaloBlur, styleValue, + XCTAssertEqualObjects(layer.iconHaloBlur, constantStyleValue, @"iconHaloBlur should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconHaloBlur = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconHaloBlur = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue, - @"Setting iconHaloBlur to a function should update icon-halo-blur."); - XCTAssertEqualObjects(layer.iconHaloBlur, styleValue, - @"iconHaloBlur should round-trip functions."); + @"Setting iconHaloBlur to a camera function should update icon-halo-blur."); + XCTAssertEqualObjects(layer.iconHaloBlur, functionStyleValue, + @"iconHaloBlur should round-trip camera functions."); + + layer.iconHaloBlur = nil; XCTAssertTrue(rawLayer->getIconHaloBlur().isUndefined(), @@ -1291,26 +1457,26 @@ - (void)testProperties { @"icon-halo-color should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconHaloColor; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; - layer.iconHaloColor = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; + layer.iconHaloColor = constantStyleValue; mbgl::style::PropertyValue propertyValue = { { 1, 0, 0, 1 } }; XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue, @"Setting iconHaloColor to a constant value should update icon-halo-color."); - XCTAssertEqualObjects(layer.iconHaloColor, styleValue, + XCTAssertEqualObjects(layer.iconHaloColor, constantStyleValue, @"iconHaloColor should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconHaloColor = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconHaloColor = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, { 1, 0, 0, 1 }}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue, - @"Setting iconHaloColor to a function should update icon-halo-color."); - XCTAssertEqualObjects(layer.iconHaloColor, styleValue, - @"iconHaloColor should round-trip functions."); + @"Setting iconHaloColor to a camera function should update icon-halo-color."); + XCTAssertEqualObjects(layer.iconHaloColor, functionStyleValue, + @"iconHaloColor should round-trip camera functions."); + + layer.iconHaloColor = nil; XCTAssertTrue(rawLayer->getIconHaloColor().isUndefined(), @@ -1325,26 +1491,26 @@ - (void)testProperties { @"icon-halo-width should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconHaloWidth; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.iconHaloWidth = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.iconHaloWidth = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue, @"Setting iconHaloWidth to a constant value should update icon-halo-width."); - XCTAssertEqualObjects(layer.iconHaloWidth, styleValue, + XCTAssertEqualObjects(layer.iconHaloWidth, constantStyleValue, @"iconHaloWidth should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconHaloWidth = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconHaloWidth = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue, - @"Setting iconHaloWidth to a function should update icon-halo-width."); - XCTAssertEqualObjects(layer.iconHaloWidth, styleValue, - @"iconHaloWidth should round-trip functions."); + @"Setting iconHaloWidth to a camera function should update icon-halo-width."); + XCTAssertEqualObjects(layer.iconHaloWidth, functionStyleValue, + @"iconHaloWidth should round-trip camera functions."); + + layer.iconHaloWidth = nil; XCTAssertTrue(rawLayer->getIconHaloWidth().isUndefined(), @@ -1359,26 +1525,26 @@ - (void)testProperties { @"icon-opacity should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconOpacity; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.iconOpacity = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.iconOpacity = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue, @"Setting iconOpacity to a constant value should update icon-opacity."); - XCTAssertEqualObjects(layer.iconOpacity, styleValue, + XCTAssertEqualObjects(layer.iconOpacity, constantStyleValue, @"iconOpacity should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconOpacity = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconOpacity = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue, - @"Setting iconOpacity to a function should update icon-opacity."); - XCTAssertEqualObjects(layer.iconOpacity, styleValue, - @"iconOpacity should round-trip functions."); + @"Setting iconOpacity to a camera function should update icon-opacity."); + XCTAssertEqualObjects(layer.iconOpacity, functionStyleValue, + @"iconOpacity should round-trip camera functions."); + + layer.iconOpacity = nil; XCTAssertTrue(rawLayer->getIconOpacity().isUndefined(), @@ -1393,32 +1559,32 @@ - (void)testProperties { @"icon-translate should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconTranslation; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue: + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue: #if TARGET_OS_IPHONE [NSValue valueWithCGVector:CGVectorMake(1, 1)] #else [NSValue valueWithMGLVector:CGVectorMake(1, -1)] #endif ]; - layer.iconTranslation = styleValue; + layer.iconTranslation = constantStyleValue; mbgl::style::PropertyValue> propertyValue = { { 1, 1 } }; XCTAssertEqual(rawLayer->getIconTranslate(), propertyValue, @"Setting iconTranslation to a constant value should update icon-translate."); - XCTAssertEqualObjects(layer.iconTranslation, styleValue, + XCTAssertEqualObjects(layer.iconTranslation, constantStyleValue, @"iconTranslation should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconTranslation = styleValue; - propertyValue = { mbgl::style::Function> { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconTranslation = functionStyleValue; + + mbgl::style::IntervalStops> intervalStops = { {{18, { 1, 1 }}} }; + propertyValue = mbgl::style::CameraFunction> { intervalStops }; + XCTAssertEqual(rawLayer->getIconTranslate(), propertyValue, - @"Setting iconTranslation to a function should update icon-translate."); - XCTAssertEqualObjects(layer.iconTranslation, styleValue, - @"iconTranslation should round-trip functions."); + @"Setting iconTranslation to a camera function should update icon-translate."); + XCTAssertEqualObjects(layer.iconTranslation, functionStyleValue, + @"iconTranslation should round-trip camera functions."); + + layer.iconTranslation = nil; XCTAssertTrue(rawLayer->getIconTranslate().isUndefined(), @@ -1433,32 +1599,38 @@ - (void)testProperties { @"icon-translate-anchor should be unset initially."); MGLStyleValue *defaultStyleValue = layer.iconTranslationAnchor; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLIconTranslationAnchor:MGLIconTranslationAnchorViewport]]; - layer.iconTranslationAnchor = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLIconTranslationAnchor:MGLIconTranslationAnchorViewport]]; + layer.iconTranslationAnchor = constantStyleValue; mbgl::style::PropertyValue propertyValue = { mbgl::style::TranslateAnchorType::Viewport }; XCTAssertEqual(rawLayer->getIconTranslateAnchor(), propertyValue, @"Setting iconTranslationAnchor to a constant value should update icon-translate-anchor."); - XCTAssertEqualObjects(layer.iconTranslationAnchor, styleValue, + XCTAssertEqualObjects(layer.iconTranslationAnchor, constantStyleValue, @"iconTranslationAnchor should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.iconTranslationAnchor = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.iconTranslationAnchor = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getIconTranslateAnchor(), propertyValue, - @"Setting iconTranslationAnchor to a function should update icon-translate-anchor."); - XCTAssertEqualObjects(layer.iconTranslationAnchor, styleValue, - @"iconTranslationAnchor should round-trip functions."); + @"Setting iconTranslationAnchor to a camera function should update icon-translate-anchor."); + XCTAssertEqualObjects(layer.iconTranslationAnchor, functionStyleValue, + @"iconTranslationAnchor should round-trip camera functions."); + + layer.iconTranslationAnchor = nil; XCTAssertTrue(rawLayer->getIconTranslateAnchor().isUndefined(), @"Unsetting iconTranslationAnchor should return icon-translate-anchor to the default value."); XCTAssertEqualObjects(layer.iconTranslationAnchor, defaultStyleValue, @"iconTranslationAnchor should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } // text-color @@ -1467,26 +1639,26 @@ - (void)testProperties { @"text-color should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textColor; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; - layer.textColor = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; + layer.textColor = constantStyleValue; mbgl::style::PropertyValue propertyValue = { { 1, 0, 0, 1 } }; XCTAssertEqual(rawLayer->getTextColor(), propertyValue, @"Setting textColor to a constant value should update text-color."); - XCTAssertEqualObjects(layer.textColor, styleValue, + XCTAssertEqualObjects(layer.textColor, constantStyleValue, @"textColor should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textColor = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textColor = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, { 1, 0, 0, 1 }}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextColor(), propertyValue, - @"Setting textColor to a function should update text-color."); - XCTAssertEqualObjects(layer.textColor, styleValue, - @"textColor should round-trip functions."); + @"Setting textColor to a camera function should update text-color."); + XCTAssertEqualObjects(layer.textColor, functionStyleValue, + @"textColor should round-trip camera functions."); + + layer.textColor = nil; XCTAssertTrue(rawLayer->getTextColor().isUndefined(), @@ -1501,26 +1673,26 @@ - (void)testProperties { @"text-halo-blur should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textHaloBlur; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.textHaloBlur = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.textHaloBlur = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue, @"Setting textHaloBlur to a constant value should update text-halo-blur."); - XCTAssertEqualObjects(layer.textHaloBlur, styleValue, + XCTAssertEqualObjects(layer.textHaloBlur, constantStyleValue, @"textHaloBlur should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textHaloBlur = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textHaloBlur = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue, - @"Setting textHaloBlur to a function should update text-halo-blur."); - XCTAssertEqualObjects(layer.textHaloBlur, styleValue, - @"textHaloBlur should round-trip functions."); + @"Setting textHaloBlur to a camera function should update text-halo-blur."); + XCTAssertEqualObjects(layer.textHaloBlur, functionStyleValue, + @"textHaloBlur should round-trip camera functions."); + + layer.textHaloBlur = nil; XCTAssertTrue(rawLayer->getTextHaloBlur().isUndefined(), @@ -1535,26 +1707,26 @@ - (void)testProperties { @"text-halo-color should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textHaloColor; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; - layer.textHaloColor = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[MGLColor redColor]]; + layer.textHaloColor = constantStyleValue; mbgl::style::PropertyValue propertyValue = { { 1, 0, 0, 1 } }; XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue, @"Setting textHaloColor to a constant value should update text-halo-color."); - XCTAssertEqualObjects(layer.textHaloColor, styleValue, + XCTAssertEqualObjects(layer.textHaloColor, constantStyleValue, @"textHaloColor should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textHaloColor = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textHaloColor = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, { 1, 0, 0, 1 }}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue, - @"Setting textHaloColor to a function should update text-halo-color."); - XCTAssertEqualObjects(layer.textHaloColor, styleValue, - @"textHaloColor should round-trip functions."); + @"Setting textHaloColor to a camera function should update text-halo-color."); + XCTAssertEqualObjects(layer.textHaloColor, functionStyleValue, + @"textHaloColor should round-trip camera functions."); + + layer.textHaloColor = nil; XCTAssertTrue(rawLayer->getTextHaloColor().isUndefined(), @@ -1569,26 +1741,26 @@ - (void)testProperties { @"text-halo-width should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textHaloWidth; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.textHaloWidth = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.textHaloWidth = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue, @"Setting textHaloWidth to a constant value should update text-halo-width."); - XCTAssertEqualObjects(layer.textHaloWidth, styleValue, + XCTAssertEqualObjects(layer.textHaloWidth, constantStyleValue, @"textHaloWidth should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textHaloWidth = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textHaloWidth = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue, - @"Setting textHaloWidth to a function should update text-halo-width."); - XCTAssertEqualObjects(layer.textHaloWidth, styleValue, - @"textHaloWidth should round-trip functions."); + @"Setting textHaloWidth to a camera function should update text-halo-width."); + XCTAssertEqualObjects(layer.textHaloWidth, functionStyleValue, + @"textHaloWidth should round-trip camera functions."); + + layer.textHaloWidth = nil; XCTAssertTrue(rawLayer->getTextHaloWidth().isUndefined(), @@ -1603,26 +1775,26 @@ - (void)testProperties { @"text-opacity should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textOpacity; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:@0xff]; - layer.textOpacity = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:@0xff]; + layer.textOpacity = constantStyleValue; mbgl::style::PropertyValue propertyValue = { 0xff }; XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue, @"Setting textOpacity to a constant value should update text-opacity."); - XCTAssertEqualObjects(layer.textOpacity, styleValue, + XCTAssertEqualObjects(layer.textOpacity, constantStyleValue, @"textOpacity should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textOpacity = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textOpacity = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue, - @"Setting textOpacity to a function should update text-opacity."); - XCTAssertEqualObjects(layer.textOpacity, styleValue, - @"textOpacity should round-trip functions."); + @"Setting textOpacity to a camera function should update text-opacity."); + XCTAssertEqualObjects(layer.textOpacity, functionStyleValue, + @"textOpacity should round-trip camera functions."); + + layer.textOpacity = nil; XCTAssertTrue(rawLayer->getTextOpacity().isUndefined(), @@ -1637,32 +1809,32 @@ - (void)testProperties { @"text-translate should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textTranslation; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue: + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue: #if TARGET_OS_IPHONE [NSValue valueWithCGVector:CGVectorMake(1, 1)] #else [NSValue valueWithMGLVector:CGVectorMake(1, -1)] #endif ]; - layer.textTranslation = styleValue; + layer.textTranslation = constantStyleValue; mbgl::style::PropertyValue> propertyValue = { { 1, 1 } }; XCTAssertEqual(rawLayer->getTextTranslate(), propertyValue, @"Setting textTranslation to a constant value should update text-translate."); - XCTAssertEqualObjects(layer.textTranslation, styleValue, + XCTAssertEqualObjects(layer.textTranslation, constantStyleValue, @"textTranslation should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textTranslation = styleValue; - propertyValue = { mbgl::style::Function> { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textTranslation = functionStyleValue; + + mbgl::style::IntervalStops> intervalStops = { {{18, { 1, 1 }}} }; + propertyValue = mbgl::style::CameraFunction> { intervalStops }; + XCTAssertEqual(rawLayer->getTextTranslate(), propertyValue, - @"Setting textTranslation to a function should update text-translate."); - XCTAssertEqualObjects(layer.textTranslation, styleValue, - @"textTranslation should round-trip functions."); + @"Setting textTranslation to a camera function should update text-translate."); + XCTAssertEqualObjects(layer.textTranslation, functionStyleValue, + @"textTranslation should round-trip camera functions."); + + layer.textTranslation = nil; XCTAssertTrue(rawLayer->getTextTranslate().isUndefined(), @@ -1677,32 +1849,38 @@ - (void)testProperties { @"text-translate-anchor should be unset initially."); MGLStyleValue *defaultStyleValue = layer.textTranslationAnchor; - MGLStyleValue *styleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLTextTranslationAnchor:MGLTextTranslationAnchorViewport]]; - layer.textTranslationAnchor = styleValue; + MGLStyleValue *constantStyleValue = [MGLStyleValue valueWithRawValue:[NSValue valueWithMGLTextTranslationAnchor:MGLTextTranslationAnchorViewport]]; + layer.textTranslationAnchor = constantStyleValue; mbgl::style::PropertyValue propertyValue = { mbgl::style::TranslateAnchorType::Viewport }; XCTAssertEqual(rawLayer->getTextTranslateAnchor(), propertyValue, @"Setting textTranslationAnchor to a constant value should update text-translate-anchor."); - XCTAssertEqualObjects(layer.textTranslationAnchor, styleValue, + XCTAssertEqualObjects(layer.textTranslationAnchor, constantStyleValue, @"textTranslationAnchor should round-trip constant values."); - styleValue = [MGLStyleValue valueWithStops:@{ - @18: styleValue, - }]; - layer.textTranslationAnchor = styleValue; - propertyValue = { mbgl::style::Function { - {{ 18, propertyValue.asConstant() }}, - 1, - }}; + MGLStyleValue * functionStyleValue = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.textTranslationAnchor = functionStyleValue; + + mbgl::style::IntervalStops intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} }; + propertyValue = mbgl::style::CameraFunction { intervalStops }; + XCTAssertEqual(rawLayer->getTextTranslateAnchor(), propertyValue, - @"Setting textTranslationAnchor to a function should update text-translate-anchor."); - XCTAssertEqualObjects(layer.textTranslationAnchor, styleValue, - @"textTranslationAnchor should round-trip functions."); + @"Setting textTranslationAnchor to a camera function should update text-translate-anchor."); + XCTAssertEqualObjects(layer.textTranslationAnchor, functionStyleValue, + @"textTranslationAnchor should round-trip camera functions."); + + layer.textTranslationAnchor = nil; XCTAssertTrue(rawLayer->getTextTranslateAnchor().isUndefined(), @"Unsetting textTranslationAnchor should return text-translate-anchor to the default value."); XCTAssertEqualObjects(layer.textTranslationAnchor, defaultStyleValue, @"textTranslationAnchor should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue 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 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"); } } diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index 56290d022dd..7df54ba65b1 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -6,8 +6,6 @@ #import "MBXAnnotationView.h" #import "MBXUserLocationAnnotationView.h" -#import "MGLFillStyleLayer.h" - #import #import @@ -72,6 +70,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsRuntimeStylingRows) { MBXSettingsRuntimeStylingRasterSource, MBXSettingsRuntimeStylingCountryLabels, MBXSettingsRuntimeStylingRouteLine, + MBXSettingsRuntimeStylingDDSPolygon, }; typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { @@ -336,6 +335,7 @@ - (void)dismissSettings:(__unused id)sender @"Style Raster Source", [NSString stringWithFormat:@"Label Countries in %@", (_usingLocaleBasedCountryLabels ? @"Local Language" : [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:[self bestLanguageForUser]])], @"Add Route Line", + @"Dynamically Style Polygon", ]]; break; case MBXSettingsMiscellaneous: @@ -497,6 +497,9 @@ - (void)performActionForSettingAtIndexPath:(NSIndexPath *)indexPath case MBXSettingsRuntimeStylingRouteLine: [self styleRouteLine]; break; + case MBXSettingsRuntimeStylingDDSPolygon: + [self stylePolygonWithDDS]; + break; default: NSAssert(NO, @"All runtime styling setting rows should be implemented"); break; @@ -739,22 +742,24 @@ - (void)addAnnotationWithCustomCallout - (void)styleWaterLayer { MGLFillStyleLayer *waterLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"water"]; - MGLStyleValue *waterColorFunction = [MGLStyleValue valueWithStops:@{ - @6.0f: [MGLStyleValue valueWithRawValue:[UIColor yellowColor]], - @8.0f: [MGLStyleValue valueWithRawValue:[UIColor blueColor]], - @10.0f: [MGLStyleValue valueWithRawValue:[UIColor redColor]], - @12.0f: [MGLStyleValue valueWithRawValue:[UIColor greenColor]], - @14.0f: [MGLStyleValue valueWithRawValue:[UIColor blueColor]], - }]; + NSDictionary *waterColorStops = @{@6.0f: [MGLStyleValue valueWithRawValue:[UIColor yellowColor]], + @8.0f: [MGLStyleValue valueWithRawValue:[UIColor blueColor]], + @10.0f: [MGLStyleValue valueWithRawValue:[UIColor redColor]], + @12.0f: [MGLStyleValue valueWithRawValue:[UIColor greenColor]], + @14.0f: [MGLStyleValue valueWithRawValue:[UIColor blueColor]]}; + MGLStyleValue *waterColorFunction = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential + cameraStops:waterColorStops + options: nil]; waterLayer.fillColor = waterColorFunction; - MGLStyleValue *fillAntialiasedFunction = [MGLStyleValue valueWithStops:@{ - @11: [MGLStyleValue valueWithRawValue:@YES], - @12: [MGLStyleValue valueWithRawValue:@NO], - @13: [MGLStyleValue valueWithRawValue:@YES], - @14: [MGLStyleValue valueWithRawValue:@NO], - @15: [MGLStyleValue valueWithRawValue:@YES], - }]; + NSDictionary *fillAntialiasedStops = @{@11: [MGLStyleValue valueWithRawValue:@YES], + @12: [MGLStyleValue valueWithRawValue:@NO], + @13: [MGLStyleValue valueWithRawValue:@YES], + @14: [MGLStyleValue valueWithRawValue:@NO], + @15: [MGLStyleValue valueWithRawValue:@YES]}; + MGLStyleValue *fillAntialiasedFunction = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeInterval + cameraStops:fillAntialiasedStops + options:nil]; waterLayer.fillAntialiased = fillAntialiasedFunction; } @@ -763,21 +768,23 @@ - (void)styleRoadLayer MGLLineStyleLayer *roadLayer = (MGLLineStyleLayer *)[self.mapView.style layerWithIdentifier:@"road-primary"]; roadLayer.lineColor = [MGLStyleValue valueWithRawValue:[UIColor blackColor]]; - MGLStyleValue *lineWidthFunction = [MGLStyleValue valueWithStops:@{ - @5: [MGLStyleValue valueWithRawValue:@5], - @10: [MGLStyleValue valueWithRawValue:@15], - @15: [MGLStyleValue valueWithRawValue:@30], - }]; - - MGLStyleValue *roadLineColor = [MGLStyleValue valueWithStops:@{ - @10: [MGLStyleValue valueWithRawValue:[UIColor purpleColor]], - @13: [MGLStyleValue valueWithRawValue:[UIColor yellowColor]], - @16: [MGLStyleValue valueWithRawValue:[UIColor cyanColor]], - }]; - roadLayer.lineColor = roadLineColor; + NSDictionary *lineWidthStops = @{@5: [MGLStyleValue valueWithRawValue:@5], + @10: [MGLStyleValue valueWithRawValue:@15], + @15: [MGLStyleValue valueWithRawValue:@30]}; + MGLStyleValue *lineWidthFunction = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential + cameraStops:lineWidthStops + options:nil]; roadLayer.lineWidth = lineWidthFunction; roadLayer.lineGapWidth = lineWidthFunction; + NSDictionary *roadLineColorStops = @{@10: [MGLStyleValue valueWithRawValue:[UIColor purpleColor]], + @13: [MGLStyleValue valueWithRawValue:[UIColor yellowColor]], + @16: [MGLStyleValue valueWithRawValue:[UIColor cyanColor]]}; + MGLStyleValue *roadLineColor = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential + cameraStops:roadLineColorStops + options: nil]; + roadLayer.lineColor = roadLineColor; + roadLayer.visible = YES; roadLayer.maximumZoomLevel = 15; roadLayer.minimumZoomLevel = 13; @@ -790,10 +797,10 @@ - (void)styleRasterLayer [self.mapView.style addSource:rasterSource]; MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"my-raster-layer" source:rasterSource]; - MGLStyleValue *opacityFunction = [MGLStyleValue valueWithStops:@{ - @20.0f: [MGLStyleValue valueWithRawValue:@1.0f], - @5.0f: [MGLStyleValue valueWithRawValue:@0.0f], - }]; + MGLStyleValue *opacityFunction = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential + cameraStops:@{@20.0f: [MGLStyleValue valueWithRawValue:@1.0f], + @5.0f: [MGLStyleValue valueWithRawValue:@0.0f]} + options:nil]; rasterLayer.rasterOpacity = opacityFunction; [self.mapView.style addLayer:rasterLayer]; } @@ -822,7 +829,7 @@ - (void)styleBuildingLayer self.mapView.style.transitionDuration = 5; self.mapView.style.transitionDelay = 1; MGLFillStyleLayer *buildingLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"building"]; - buildingLayer.fillColor = [MGLStyleValue valueWithRawValue:[UIColor blackColor]]; + buildingLayer.fillColor = [MGLStyleValue valueWithRawValue:[UIColor purpleColor]]; } - (void)styleFerryLayer @@ -857,18 +864,6 @@ - (void)styleFilteredFill }); } -+ (MGLStyleConstantValue *)testEnum:(NSUInteger)value type:(const char *)type -{ - return [MGLStyleConstantValue valueWithRawValue:[NSValue value:&value withObjCType:type]]; -} - -+ (MGLStyleFunction *)testEnumFunction:(NSUInteger)value type:(const char *)type -{ - return [MGLStyleFunction valueWithStops:@{ - @18: [self testEnum:value type:type], - }]; -} - - (void)styleFilteredLines { // set style and focus on lower 48 @@ -1204,6 +1199,48 @@ - (void)styleRouteLine [self.mapView.style addLayer:routeLayer]; } +- (void)stylePolygonWithDDS { + CLLocationCoordinate2D leftCoords[] = { + {37.73081027834234, -122.49412536621094}, + {37.7566013348511, -122.49412536621094}, + {37.7566013348511, -122.46253967285156}, + {37.73081027834234, -122.46253967285156}, + {37.73081027834234, -122.49412536621094}, + }; + CLLocationCoordinate2D rightCoords[] = { + {37.73135334055843, -122.44640350341795}, + {37.75741564287944, -122.44640350341795}, + {37.75741564287944, -122.41310119628906}, + {37.73135334055843, -122.41310119628906}, + {37.73135334055843, -122.44640350341795}, + }; + MGLPolygonFeature *leftFeature = [MGLPolygonFeature polygonWithCoordinates:leftCoords count:5]; + leftFeature.attributes = @{@"fill": @(YES)}; + + MGLPolygonFeature *rightFeature = [MGLPolygonFeature polygonWithCoordinates:rightCoords count:5]; + rightFeature.attributes = @{@"opacity": @(0.5)}; + + MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"shape-source" features:@[leftFeature, rightFeature] options:nil]; + [self.mapView.style addSource:shapeSource]; + + // source, categorical function that sets any feature with a "fill" attribute value of true to red color and anything without to green + MGLFillStyleLayer *fillStyleLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fill-layer" source:shapeSource]; + NSDictionary *stops = @{@(YES): [MGLStyleValue valueWithRawValue:[UIColor greenColor]]}; + NSDictionary *fillColorOptions = @{MGLStyleFunctionOptionDefaultValue: [MGLStyleValue valueWithRawValue:[UIColor redColor]]}; + fillStyleLayer.fillColor = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeCategorical + sourceStops:stops + attributeName:@"fill" + options:fillColorOptions]; + + // source, identity function that sets any feature with an "opacity" attribute to use that value and anything without to 1.0 + NSDictionary *fillOpacityOptions = @{MGLStyleFunctionOptionDefaultValue: [MGLStyleValue valueWithRawValue:@(1.0)]}; + fillStyleLayer.fillOpacity = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeIdentity + sourceStops:nil + attributeName:@"opacity" + options:fillOpacityOptions]; + [self.mapView.style addLayer:fillStyleLayer]; +} + - (void)styleLabelLanguageForLayersNamed:(NSArray *)layers { _usingLocaleBasedCountryLabels = !_usingLocaleBasedCountryLabels; @@ -1219,8 +1256,9 @@ - (void)styleLabelLanguageForLayersNamed:(NSArray *)layers if ([label.rawValue hasPrefix:@"{name"]) { layer.text = [MGLStyleValue valueWithRawValue:language]; } - } else if ([layer.text isKindOfClass:[MGLStyleFunction class]]) { - MGLStyleFunction *function = (MGLStyleFunction *)layer.text; + } + else if ([layer.text isKindOfClass:[MGLCameraStyleFunction class]]) { + MGLCameraStyleFunction *function = (MGLCameraStyleFunction *)layer.text; [function.stops enumerateKeysAndObjectsUsingBlock:^(id zoomLevel, id stop, BOOL *done) { if ([stop isKindOfClass:[MGLStyleConstantValue class]]) { MGLStyleConstantValue *label = (MGLStyleConstantValue *)stop; diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index c5db2be7e03..31bc376175d 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -906,8 +906,8 @@ DA72620A1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm */, 353933FA1D3FB7C0003F57D7 /* MGLRasterStyleLayer.h */, 35136D411D42274500C20EFD /* MGLRasterStyleLayer.mm */, - 35D13AB51D3D15E300AFB4E0 /* MGLStyleLayer.h */, 35E79F1F1D41266300957B9E /* MGLStyleLayer_Private.h */, + 35D13AB51D3D15E300AFB4E0 /* MGLStyleLayer.h */, 35D13AB61D3D15E300AFB4E0 /* MGLStyleLayer.mm */, 353933FD1D3FB7DD003F57D7 /* MGLSymbolStyleLayer.h */, 35136D441D42275100C20EFD /* MGLSymbolStyleLayer.mm */, diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m index 225bb4d3af1..62ddd2ce60b 100644 --- a/platform/macos/app/MapDocument.m +++ b/platform/macos/app/MapDocument.m @@ -373,8 +373,9 @@ - (void)updateLabels { if ([layer.text isKindOfClass:[MGLStyleConstantValue class]]) { NSString *textField = [(MGLStyleConstantValue *)layer.text rawValue]; layer.text = [MGLStyleValue valueWithRawValue:stringByLocalizingString(textField)]; - } else if ([layer.text isKindOfClass:[MGLStyleFunction class]]) { - MGLStyleFunction *function = (MGLStyleFunction *)layer.text; + } + else if ([layer.text isKindOfClass:[MGLCameraStyleFunction class]]) { + MGLCameraStyleFunction *function = (MGLCameraStyleFunction *)layer.text; NSMutableDictionary *stops = function.stops.mutableCopy; [stops enumerateKeysAndObjectsUsingBlock:^(NSNumber *zoomLevel, MGLStyleConstantValue *stop, BOOL *done) { NSString *textField = stop.rawValue;