diff options
author | Lauren Budorick <lauren@mapbox.com> | 2017-04-27 15:56:55 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-27 15:56:55 -0700 |
commit | f6e79d70735361438655f279c8699a786d25458c (patch) | |
tree | cc01ae7aba097bae4aa84beb12ac6b8f34f4d51a /platform/darwin | |
parent | 839ad87f37a4880804fb4c79157d998ac59954b5 (diff) | |
download | qtlocation-mapboxgl-f6e79d70735361438655f279c8699a786d25458c.tar.gz |
[core] Render fill-extrusion layers (#8431)
Diffstat (limited to 'platform/darwin')
-rw-r--r-- | platform/darwin/docs/guides/For Style Authors.md.ejs | 2 | ||||
-rw-r--r-- | platform/darwin/scripts/generate-style-code.js | 5 | ||||
-rw-r--r-- | platform/darwin/scripts/style-spec-cocoa-conventions-v8.json | 4 | ||||
-rw-r--r-- | platform/darwin/scripts/style-spec-overrides-v8.json | 14 | ||||
-rw-r--r-- | platform/darwin/src/MGLFillExtrusionStyleLayer.h | 364 | ||||
-rw-r--r-- | platform/darwin/src/MGLFillExtrusionStyleLayer.mm | 335 | ||||
-rw-r--r-- | platform/darwin/src/MGLStyle.mm | 4 | ||||
-rw-r--r-- | platform/darwin/src/MGLStyleLayer.h.ejs | 2 | ||||
-rw-r--r-- | platform/darwin/test/MGLDocumentationExampleTests.swift | 16 | ||||
-rw-r--r-- | platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm | 445 | ||||
-rw-r--r-- | platform/darwin/test/MGLStyleLayerTests.mm.ejs | 2 |
11 files changed, 1185 insertions, 8 deletions
diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs index 86f8c46f53..2d9ce635b8 100644 --- a/platform/darwin/docs/guides/For Style Authors.md.ejs +++ b/platform/darwin/docs/guides/For Style Authors.md.ejs @@ -240,7 +240,7 @@ whose names differ from the style specification are listed below: <% for (const type in renamedProperties) { -%> <% if (renamedProperties.hasOwnProperty(type)) { -%> -### <%- camelize(type) %> style layers +### <%- camelize(unhyphenate(type)) %> style layers In style JSON | In Objective-C | In Swift --------------|----------------|--------- diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js index 7e798154e4..5d5adbbef6 100644 --- a/platform/darwin/scripts/generate-style-code.js +++ b/platform/darwin/scripts/generate-style-code.js @@ -13,11 +13,6 @@ const suffix = 'StyleLayer'; let spec = _.merge(require('../../../mapbox-gl-js/src/style-spec/reference/v8'), require('./style-spec-overrides-v8.json')); -/// -// Temporarily IGNORE layers that are in the spec yet still not supported in mbgl core -/// -delete spec.layer.type.values['fill-extrusion']; - // Rename properties and keep `original` for use with setters and getters _.forOwn(cocoaConventions, function (properties, kind) { _.forOwn(properties, function (newName, oldName) { diff --git a/platform/darwin/scripts/style-spec-cocoa-conventions-v8.json b/platform/darwin/scripts/style-spec-cocoa-conventions-v8.json index 9d80ff3896..830b6d69f9 100644 --- a/platform/darwin/scripts/style-spec-cocoa-conventions-v8.json +++ b/platform/darwin/scripts/style-spec-cocoa-conventions-v8.json @@ -30,6 +30,10 @@ "fill-translate": "fill-translation", "fill-translate-anchor": "fill-translation-anchor" }, + "paint_fill-extrusion": { + "fill-extrusion-translate": "fill-extrusion-translation", + "fill-extrusion-translate-anchor": "fill-extrusion-translation-anchor" + }, "paint_raster": { "raster-brightness-min": "minimum-raster-brightness", "raster-brightness-max": "maximum-raster-brightness", diff --git a/platform/darwin/scripts/style-spec-overrides-v8.json b/platform/darwin/scripts/style-spec-overrides-v8.json index 28740d458b..a594ef2957 100644 --- a/platform/darwin/scripts/style-spec-overrides-v8.json +++ b/platform/darwin/scripts/style-spec-overrides-v8.json @@ -5,6 +5,9 @@ "fill": { "doc": "An `MGLFillStyleLayer` is a style layer that renders one or more filled (and optionally stroked) polygons on the map.\n\nUse a fill style layer to configure the visual appearance of polygon or multipolygon features in vector tiles loaded by an `MGLVectorSource` object or `MGLPolygon`, `MGLPolygonFeature`, `MGLMultiPolygon`, or `MGLMultiPolygonFeature` instances in an `MGLShapeSource` object." }, + "fill-extrusion": { + "doc": "An `MGLFillExtrusionStyleLayer` is a style layer that renders one or more 3D extruded polygons on the map.\n\nUse a fill-extrusion style layer to configure the visual appearance of polygon or multipolygon features in vector tiles loaded by an `MGLVectorSource` object or `MGLPolygon`, `MGLPolygonFeature`, `MGLMultiPolygon`, or `MGLMultiPolygonFeature` instances in an `MGLShapeSource` object." + }, "line": { "doc": "An `MGLLineStyleLayer` is a style layer that renders one or more stroked polylines on the map.\n\nUse a line style layer to configure the visual appearance of polyline or multipolyline features in vector tiles loaded by an `MGLVectorSource` object or `MGLPolyline`, `MGLPolylineFeature`, `MGLMultiPolyline`, or `MGLMultiPolylineFeature` instances in an `MGLShapeSource` object." }, @@ -50,6 +53,17 @@ "doc": "Name of image in style images to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512)." } }, + "paint_fill-extrusion": { + "fill-extrusion-pattern": { + "doc": "Name of image in style images to use for drawing image fill-extrusions. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512)." + }, + "fill-extrusion-translate": { + "doc": "The geometry's offset." + }, + "fill-extrusion-color": { + "doc": "The base color of this layer. The extrusion's surfaces will be shaded differently based on this color in combination with the `light` settings. If this color is specified with an alpha component, the alpha component will be ignored; use `fill-extrusion-opacity` to set layer opacityco." + } + }, "paint_line": { "line-pattern": { "doc": "Name of image in style images to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512)." diff --git a/platform/darwin/src/MGLFillExtrusionStyleLayer.h b/platform/darwin/src/MGLFillExtrusionStyleLayer.h new file mode 100644 index 0000000000..84f6bedde4 --- /dev/null +++ b/platform/darwin/src/MGLFillExtrusionStyleLayer.h @@ -0,0 +1,364 @@ +// This file is generated. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`. + +#import "MGLFoundation.h" +#import "MGLStyleValue.h" +#import "MGLVectorStyleLayer.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Controls the translation reference point. + + Values of this type are used in the `MGLFillExtrusionStyleLayer.fillExtrusionTranslationAnchor` + property. + */ +typedef NS_ENUM(NSUInteger, MGLFillExtrusionTranslationAnchor) { + /** + The fill extrusion is translated relative to the map. + */ + MGLFillExtrusionTranslationAnchorMap, + /** + The fill extrusion is translated relative to the viewport. + */ + MGLFillExtrusionTranslationAnchorViewport, +}; + +/** + An `MGLFillExtrusionStyleLayer` is a style layer that renders one or more 3D + extruded polygons on the map. + + Use a fill-extrusion style layer to configure the visual appearance of polygon + or multipolygon features in vector tiles loaded by an `MGLVectorSource` object + or `MGLPolygon`, `MGLPolygonFeature`, `MGLMultiPolygon`, or + `MGLMultiPolygonFeature` instances in an `MGLShapeSource` object. + + You can access an existing fill-extrusion style layer using the + `-[MGLStyle layerWithIdentifier:]` method if you know its identifier; + otherwise, find it using the `MGLStyle.layers` property. You can also create a + new fill-extrusion style layer and add it to the style using a method such as + `-[MGLStyle addLayer:]`. + + ### Example + + ```swift + let layer = MGLFillExtrusionStyleLayer(identifier: "buildings", source: buildings) + layer.sourceLayerIdentifier = "building" + layer.fillExtrusionHeight = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "height", options: nil) + layer.fillExtrusionBase = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "min_height", options: nil) + layer.predicate = NSPredicate(format: "extrude == TRUE") + mapView.style?.addLayer(layer) + ``` + */ +MGL_EXPORT +@interface MGLFillExtrusionStyleLayer : MGLVectorStyleLayer + +/** + Returns a fill-extrusion style layer initialized with an identifier and source. + + After initializing and configuring the style layer, add it to a map view’s + style using the `-[MGLStyle addLayer:]` or + `-[MGLStyle insertLayer:belowLayer:]` method. + + @param identifier A string that uniquely identifies the source in the style to + which it is added. + @param source The source from which to obtain the data to style. If the source + has not yet been added to the current style, the behavior is undefined. + @return An initialized foreground style layer. + */ +- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source; + +#pragma mark - Accessing the Paint Attributes + +/** + The height with which to extrude the base of this layer. Must be less than or + equal to `fillExtrusionHeight`. + + This property is measured in meters. + + The default value of this property is an `MGLStyleValue` object containing an + `NSNumber` object containing the float `0`. Set this property to `nil` to reset + it to the default value. + + This property is only applied to the style if `fillExtrusionHeight` is + non-`nil`. Otherwise, it is ignored. + + You can set this property to an instance of: + + * `MGLConstantStyleValue` + * `MGLCameraStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + * `MGLSourceStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + * `MGLInterpolationModeCategorical` + * `MGLInterpolationModeIdentity` + * `MGLCompositeStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + * `MGLInterpolationModeCategorical` + */ +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *fillExtrusionBase; + +/** + The transition affecting any changes to this layer’s `fillExtrusionBase` property. + + This property corresponds to the `fill-extrusion-base-transition` property in the style JSON file format. +*/ +@property (nonatomic) MGLTransition fillExtrusionBaseTransition; + +#if TARGET_OS_IPHONE +/** + The base color of this layer. The extrusion's surfaces will be shaded + differently based on this color in combination with the `light` settings. If + this color is specified with an alpha component, the alpha component will be + ignored; use `fillExtrusionOpacity` to set layer opacityco. + + The default value of this property is an `MGLStyleValue` object containing + `UIColor.blackColor`. Set this property to `nil` to reset it to the default + value. + + This property is only applied to the style if `fillExtrusionPattern` is set to + `nil`. Otherwise, it is ignored. + + You can set this property to an instance of: + + * `MGLConstantStyleValue` + * `MGLCameraStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + * `MGLSourceStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + * `MGLInterpolationModeCategorical` + * `MGLInterpolationModeIdentity` + * `MGLCompositeStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + * `MGLInterpolationModeCategorical` + */ +@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *fillExtrusionColor; +#else +/** + The base color of this layer. The extrusion's surfaces will be shaded + differently based on this color in combination with the `light` settings. If + this color is specified with an alpha component, the alpha component will be + ignored; use `fillExtrusionOpacity` to set layer opacityco. + + The default value of this property is an `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 `fillExtrusionPattern` is set to + `nil`. Otherwise, it is ignored. + + You can set this property to an instance of: + + * `MGLConstantStyleValue` + * `MGLCameraStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + * `MGLSourceStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + * `MGLInterpolationModeCategorical` + * `MGLInterpolationModeIdentity` + * `MGLCompositeStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + * `MGLInterpolationModeCategorical` + */ +@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *fillExtrusionColor; +#endif + +/** + The transition affecting any changes to this layer’s `fillExtrusionColor` property. + + This property corresponds to the `fill-extrusion-color-transition` property in the style JSON file format. +*/ +@property (nonatomic) MGLTransition fillExtrusionColorTransition; + +/** + The height with which to extrude this layer. + + This property is measured in meters. + + The default value of this property is an `MGLStyleValue` object containing an + `NSNumber` object containing the float `0`. Set this property to `nil` to reset + it to the default value. + + You can set this property to an instance of: + + * `MGLConstantStyleValue` + * `MGLCameraStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + * `MGLSourceStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + * `MGLInterpolationModeCategorical` + * `MGLInterpolationModeIdentity` + * `MGLCompositeStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + * `MGLInterpolationModeCategorical` + */ +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *fillExtrusionHeight; + +/** + The transition affecting any changes to this layer’s `fillExtrusionHeight` property. + + This property corresponds to the `fill-extrusion-height-transition` property in the style JSON file format. +*/ +@property (nonatomic) MGLTransition fillExtrusionHeightTransition; + +/** + The opacity of the entire fill extrusion layer. This is rendered on a + per-layer, not per-feature, basis, and data-driven styling is not available. + + The default value of this property is an `MGLStyleValue` object containing an + `NSNumber` object containing the float `1`. Set this property to `nil` to reset + it to the default value. + + You can set this property to an instance of: + + * `MGLConstantStyleValue` + * `MGLCameraStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + */ +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *fillExtrusionOpacity; + +/** + The transition affecting any changes to this layer’s `fillExtrusionOpacity` property. + + This property corresponds to the `fill-extrusion-opacity-transition` property in the style JSON file format. +*/ +@property (nonatomic) MGLTransition fillExtrusionOpacityTransition; + +/** + Name of image in style images to use for drawing image fill-extrusions. For + seamless patterns, image width and height must be a factor of two (2, 4, 8, + ..., 512). + + You can set this property to an instance of: + + * `MGLConstantStyleValue` + * `MGLCameraStyleFunction` with an interpolation mode of + `MGLInterpolationModeInterval` + */ +@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *fillExtrusionPattern; + +/** + The transition affecting any changes to this layer’s `fillExtrusionPattern` property. + + This property corresponds to the `fill-extrusion-pattern-transition` property in the style JSON file format. +*/ +@property (nonatomic) MGLTransition fillExtrusionPatternTransition; + +#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 <a + href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-extrusion-translate"><code>fill-extrusion-translate</code></a> + layout property in the Mapbox Style Specification. + + You can set this property to an instance of: + + * `MGLConstantStyleValue` + * `MGLCameraStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + */ +@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillExtrusionTranslation; +#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 <a + href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-extrusion-translate"><code>fill-extrusion-translate</code></a> + layout property in the Mapbox Style Specification. + + You can set this property to an instance of: + + * `MGLConstantStyleValue` + * `MGLCameraStyleFunction` with an interpolation mode of: + * `MGLInterpolationModeExponential` + * `MGLInterpolationModeInterval` + */ +@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillExtrusionTranslation; +#endif + +/** + The transition affecting any changes to this layer’s `fillExtrusionTranslation` property. + + This property corresponds to the `fill-extrusion-translate-transition` property in the style JSON file format. +*/ +@property (nonatomic) MGLTransition fillExtrusionTranslationTransition; + +@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillExtrusionTranslate __attribute__((unavailable("Use fillExtrusionTranslation instead."))); + +/** + Controls the translation reference point. + + The default value of this property is an `MGLStyleValue` object containing an + `NSValue` object containing `MGLFillExtrusionTranslationAnchorMap`. Set this + property to `nil` to reset it to the default value. + + This property is only applied to the style if `fillExtrusionTranslation` is + non-`nil`. Otherwise, it is ignored. + + This attribute corresponds to the <a + href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-extrusion-translate-anchor"><code>fill-extrusion-translate-anchor</code></a> + layout property in the Mapbox Style Specification. + + You can set this property to an instance of: + + * `MGLConstantStyleValue` + * `MGLCameraStyleFunction` with an interpolation mode of + `MGLInterpolationModeInterval` + */ +@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillExtrusionTranslationAnchor; + +@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillExtrusionTranslateAnchor __attribute__((unavailable("Use fillExtrusionTranslationAnchor instead."))); + +@end + +/** + Methods for wrapping an enumeration value for a style layer attribute in an + `MGLFillExtrusionStyleLayer` object and unwrapping its raw value. + */ +@interface NSValue (MGLFillExtrusionStyleLayerAdditions) + +#pragma mark Working with Fill extrusion Style Layer Attribute Values + +/** + Creates a new value object containing the given `MGLFillExtrusionTranslationAnchor` enumeration. + + @param fillExtrusionTranslationAnchor The value for the new object. + @return A new value object that contains the enumeration value. + */ ++ (instancetype)valueWithMGLFillExtrusionTranslationAnchor:(MGLFillExtrusionTranslationAnchor)fillExtrusionTranslationAnchor; + +/** + The `MGLFillExtrusionTranslationAnchor` enumeration representation of the value. + */ +@property (readonly) MGLFillExtrusionTranslationAnchor MGLFillExtrusionTranslationAnchorValue; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLFillExtrusionStyleLayer.mm b/platform/darwin/src/MGLFillExtrusionStyleLayer.mm new file mode 100644 index 0000000000..b00ed8e09f --- /dev/null +++ b/platform/darwin/src/MGLFillExtrusionStyleLayer.mm @@ -0,0 +1,335 @@ +// This file is generated. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`. + +#import "MGLSource.h" +#import "NSPredicate+MGLAdditions.h" +#import "NSDate+MGLAdditions.h" +#import "MGLStyleLayer_Private.h" +#import "MGLStyleValue_Private.h" +#import "MGLFillExtrusionStyleLayer.h" + +#include <mbgl/style/transition_options.hpp> +#include <mbgl/style/layers/fill_extrusion_layer.hpp> + +namespace mbgl { + + MBGL_DEFINE_ENUM(MGLFillExtrusionTranslationAnchor, { + { MGLFillExtrusionTranslationAnchorMap, "map" }, + { MGLFillExtrusionTranslationAnchorViewport, "viewport" }, + }); + +} + +@interface MGLFillExtrusionStyleLayer () + +@property (nonatomic, readonly) mbgl::style::FillExtrusionLayer *rawLayer; + +@end + +@implementation MGLFillExtrusionStyleLayer + +- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source +{ + auto layer = std::make_unique<mbgl::style::FillExtrusionLayer>(identifier.UTF8String, source.identifier.UTF8String); + return self = [super initWithPendingLayer:std::move(layer)]; +} + +- (mbgl::style::FillExtrusionLayer *)rawLayer +{ + return (mbgl::style::FillExtrusionLayer *)super.rawLayer; +} + +- (NSString *)sourceIdentifier +{ + MGLAssertStyleLayerIsValid(); + + return @(self.rawLayer->getSourceID().c_str()); +} + +- (NSString *)sourceLayerIdentifier +{ + MGLAssertStyleLayerIsValid(); + + auto layerID = self.rawLayer->getSourceLayer(); + return layerID.empty() ? nil : @(layerID.c_str()); +} + +- (void)setSourceLayerIdentifier:(NSString *)sourceLayerIdentifier +{ + MGLAssertStyleLayerIsValid(); + + self.rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: ""); +} + +- (void)setPredicate:(NSPredicate *)predicate +{ + MGLAssertStyleLayerIsValid(); + + self.rawLayer->setFilter(predicate ? predicate.mgl_filter : mbgl::style::NullFilter()); +} + +- (NSPredicate *)predicate +{ + MGLAssertStyleLayerIsValid(); + + return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()]; +} + +#pragma mark - Accessing the Paint Attributes + +- (void)setFillExtrusionBase:(MGLStyleValue<NSNumber *> *)fillExtrusionBase { + MGLAssertStyleLayerIsValid(); + + auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(fillExtrusionBase); + self.rawLayer->setFillExtrusionBase(mbglValue); +} + +- (MGLStyleValue<NSNumber *> *)fillExtrusionBase { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getFillExtrusionBase(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultFillExtrusionBase()); + } + return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue); +} + +- (void)setFillExtrusionBaseTransition:(MGLTransition )transition { + MGLAssertStyleLayerIsValid(); + + mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } }; + self.rawLayer->setFillExtrusionBaseTransition(options); +} + +- (MGLTransition)fillExtrusionBaseTransition { + MGLAssertStyleLayerIsValid(); + + mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getFillExtrusionBaseTransition(); + MGLTransition transition; + transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero())); + transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero())); + + return transition; +} + +- (void)setFillExtrusionColor:(MGLStyleValue<MGLColor *> *)fillExtrusionColor { + MGLAssertStyleLayerIsValid(); + + auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(fillExtrusionColor); + self.rawLayer->setFillExtrusionColor(mbglValue); +} + +- (MGLStyleValue<MGLColor *> *)fillExtrusionColor { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getFillExtrusionColor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultFillExtrusionColor()); + } + return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue); +} + +- (void)setFillExtrusionColorTransition:(MGLTransition )transition { + MGLAssertStyleLayerIsValid(); + + mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } }; + self.rawLayer->setFillExtrusionColorTransition(options); +} + +- (MGLTransition)fillExtrusionColorTransition { + MGLAssertStyleLayerIsValid(); + + mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getFillExtrusionColorTransition(); + MGLTransition transition; + transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero())); + transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero())); + + return transition; +} + +- (void)setFillExtrusionHeight:(MGLStyleValue<NSNumber *> *)fillExtrusionHeight { + MGLAssertStyleLayerIsValid(); + + auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(fillExtrusionHeight); + self.rawLayer->setFillExtrusionHeight(mbglValue); +} + +- (MGLStyleValue<NSNumber *> *)fillExtrusionHeight { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getFillExtrusionHeight(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultFillExtrusionHeight()); + } + return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue); +} + +- (void)setFillExtrusionHeightTransition:(MGLTransition )transition { + MGLAssertStyleLayerIsValid(); + + mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } }; + self.rawLayer->setFillExtrusionHeightTransition(options); +} + +- (MGLTransition)fillExtrusionHeightTransition { + MGLAssertStyleLayerIsValid(); + + mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getFillExtrusionHeightTransition(); + MGLTransition transition; + transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero())); + transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero())); + + return transition; +} + +- (void)setFillExtrusionOpacity:(MGLStyleValue<NSNumber *> *)fillExtrusionOpacity { + MGLAssertStyleLayerIsValid(); + + auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(fillExtrusionOpacity); + self.rawLayer->setFillExtrusionOpacity(mbglValue); +} + +- (MGLStyleValue<NSNumber *> *)fillExtrusionOpacity { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getFillExtrusionOpacity(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultFillExtrusionOpacity()); + } + return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); +} + +- (void)setFillExtrusionOpacityTransition:(MGLTransition )transition { + MGLAssertStyleLayerIsValid(); + + mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } }; + self.rawLayer->setFillExtrusionOpacityTransition(options); +} + +- (MGLTransition)fillExtrusionOpacityTransition { + MGLAssertStyleLayerIsValid(); + + mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getFillExtrusionOpacityTransition(); + MGLTransition transition; + transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero())); + transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero())); + + return transition; +} + +- (void)setFillExtrusionPattern:(MGLStyleValue<NSString *> *)fillExtrusionPattern { + MGLAssertStyleLayerIsValid(); + + auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(fillExtrusionPattern); + self.rawLayer->setFillExtrusionPattern(mbglValue); +} + +- (MGLStyleValue<NSString *> *)fillExtrusionPattern { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getFillExtrusionPattern(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(self.rawLayer->getDefaultFillExtrusionPattern()); + } + return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue); +} + +- (void)setFillExtrusionPatternTransition:(MGLTransition )transition { + MGLAssertStyleLayerIsValid(); + + mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } }; + self.rawLayer->setFillExtrusionPatternTransition(options); +} + +- (MGLTransition)fillExtrusionPatternTransition { + MGLAssertStyleLayerIsValid(); + + mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getFillExtrusionPatternTransition(); + MGLTransition transition; + transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero())); + transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero())); + + return transition; +} + +- (void)setFillExtrusionTranslation:(MGLStyleValue<NSValue *> *)fillExtrusionTranslation { + MGLAssertStyleLayerIsValid(); + + auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toInterpolatablePropertyValue(fillExtrusionTranslation); + self.rawLayer->setFillExtrusionTranslate(mbglValue); +} + +- (MGLStyleValue<NSValue *> *)fillExtrusionTranslation { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getFillExtrusionTranslate(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(self.rawLayer->getDefaultFillExtrusionTranslate()); + } + return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue); +} + +- (void)setFillExtrusionTranslationTransition:(MGLTransition )transition { + MGLAssertStyleLayerIsValid(); + + mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } }; + self.rawLayer->setFillExtrusionTranslateTransition(options); +} + +- (MGLTransition)fillExtrusionTranslationTransition { + MGLAssertStyleLayerIsValid(); + + mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getFillExtrusionTranslateTransition(); + MGLTransition transition; + transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero())); + transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero())); + + return transition; +} + +- (void)setFillExtrusionTranslate:(MGLStyleValue<NSValue *> *)fillExtrusionTranslate { +} + +- (MGLStyleValue<NSValue *> *)fillExtrusionTranslate { + return self.fillExtrusionTranslation; +} + +- (void)setFillExtrusionTranslationAnchor:(MGLStyleValue<NSValue *> *)fillExtrusionTranslationAnchor { + MGLAssertStyleLayerIsValid(); + + auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillExtrusionTranslationAnchor>().toEnumPropertyValue(fillExtrusionTranslationAnchor); + self.rawLayer->setFillExtrusionTranslateAnchor(mbglValue); +} + +- (MGLStyleValue<NSValue *> *)fillExtrusionTranslationAnchor { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getFillExtrusionTranslateAnchor(); + if (propertyValue.isUndefined()) { + return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillExtrusionTranslationAnchor>().toEnumStyleValue(self.rawLayer->getDefaultFillExtrusionTranslateAnchor()); + } + return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillExtrusionTranslationAnchor>().toEnumStyleValue(propertyValue); +} + +- (void)setFillExtrusionTranslateAnchor:(MGLStyleValue<NSValue *> *)fillExtrusionTranslateAnchor { +} + +- (MGLStyleValue<NSValue *> *)fillExtrusionTranslateAnchor { + return self.fillExtrusionTranslationAnchor; +} + +@end + +@implementation NSValue (MGLFillExtrusionStyleLayerAdditions) + ++ (NSValue *)valueWithMGLFillExtrusionTranslationAnchor:(MGLFillExtrusionTranslationAnchor)fillExtrusionTranslationAnchor { + return [NSValue value:&fillExtrusionTranslationAnchor withObjCType:@encode(MGLFillExtrusionTranslationAnchor)]; +} + +- (MGLFillExtrusionTranslationAnchor)MGLFillExtrusionTranslationAnchorValue { + MGLFillExtrusionTranslationAnchor fillExtrusionTranslationAnchor; + [self getValue:&fillExtrusionTranslationAnchor]; + return fillExtrusionTranslationAnchor; +} + +@end diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm index a4cf8d9cce..81b6446e7f 100644 --- a/platform/darwin/src/MGLStyle.mm +++ b/platform/darwin/src/MGLStyle.mm @@ -3,6 +3,7 @@ #import "MGLMapView_Private.h" #import "MGLStyleLayer.h" #import "MGLFillStyleLayer.h" +#import "MGLFillExtrusionStyleLayer.h" #import "MGLLineStyleLayer.h" #import "MGLCircleStyleLayer.h" #import "MGLSymbolStyleLayer.h" @@ -28,6 +29,7 @@ #include <mbgl/util/default_styles.hpp> #include <mbgl/style/image.hpp> #include <mbgl/style/layers/fill_layer.hpp> +#include <mbgl/style/layers/fill_extrusion_layer.hpp> #include <mbgl/style/layers/line_layer.hpp> #include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/layers/raster_layer.hpp> @@ -332,6 +334,8 @@ static NSURL *MGLStyleURL_emerald; if (auto fillLayer = rawLayer->as<mbgl::style::FillLayer>()) { return [[MGLFillStyleLayer alloc] initWithRawLayer:fillLayer]; + } else if (auto fillExtrusionLayer = rawLayer->as<mbgl::style::FillExtrusionLayer>()) { + return [[MGLFillExtrusionStyleLayer alloc] initWithRawLayer:fillExtrusionLayer]; } else if (auto lineLayer = rawLayer->as<mbgl::style::LineLayer>()) { return [[MGLLineStyleLayer alloc] initWithRawLayer:lineLayer]; } else if (auto symbolLayer = rawLayer->as<mbgl::style::SymbolLayer>()) { diff --git a/platform/darwin/src/MGLStyleLayer.h.ejs b/platform/darwin/src/MGLStyleLayer.h.ejs index e29ea4611d..df42621c6d 100644 --- a/platform/darwin/src/MGLStyleLayer.h.ejs +++ b/platform/darwin/src/MGLStyleLayer.h.ejs @@ -161,7 +161,7 @@ which it is added. */ @interface NSValue (MGL<%- camelize(type) %>StyleLayerAdditions) -#pragma mark Working with <%- camelize(type) %> Style Layer Attribute Values +#pragma mark Working with <%- camelize(unhyphenate(type)) %> Style Layer Attribute Values <% for (let property of enumProperties) { -%> /** diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift index 177d97d523..6d2dc597a9 100644 --- a/platform/darwin/test/MGLDocumentationExampleTests.swift +++ b/platform/darwin/test/MGLDocumentationExampleTests.swift @@ -158,6 +158,22 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate { XCTAssertNotNil(mapView.style?.layer(withIdentifier: "parks")) } + + func testMGLFillExtrusionStyleLayer() { + let buildings = MGLVectorSource(identifier: "buildings", configurationURL: URL(string: "https://example.com/style.json")!) + mapView.style?.addSource(buildings) + + //#-example-code + let layer = MGLFillExtrusionStyleLayer(identifier: "buildings", source: buildings) + layer.sourceLayerIdentifier = "building" + layer.fillExtrusionHeight = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "height", options: nil) + layer.fillExtrusionBase = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "min_height", options: nil) + layer.predicate = NSPredicate(format: "extrude == TRUE") + mapView.style?.addLayer(layer) + //#-end-example-code + + XCTAssertNotNil(mapView.style?.layer(withIdentifier: "buildings")) + } func testMGLSymbolStyleLayer() { let pois = MGLVectorSource(identifier: "pois", configurationURL: URL(string: "https://example.com/style.json")!) diff --git a/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm b/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm new file mode 100644 index 0000000000..5d99c815ea --- /dev/null +++ b/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm @@ -0,0 +1,445 @@ +// This file is generated. +// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`. + +#import "MGLStyleLayerTests.h" +#import "../../darwin/src/NSDate+MGLAdditions.h" + +#import "MGLStyleLayer_Private.h" + +#include <mbgl/style/layers/fill_extrusion_layer.hpp> +#include <mbgl/style/transition_options.hpp> + +@interface MGLFillExtrusionLayerTests : MGLStyleLayerTests +@end + +@implementation MGLFillExtrusionLayerTests + ++ (NSString *)layerType { + return @"fill-extrusion"; +} + +- (void)testPredicates { + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil]; + MGLFillExtrusionStyleLayer *layer = [[MGLFillExtrusionStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; + + XCTAssertNil(layer.sourceLayerIdentifier); + layer.sourceLayerIdentifier = @"layerID"; + XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID"); + layer.sourceLayerIdentifier = nil; + XCTAssertNil(layer.sourceLayerIdentifier); + + XCTAssertNil(layer.predicate); + layer.predicate = [NSPredicate predicateWithValue:NO]; + XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]); + layer.predicate = nil; + XCTAssertNil(layer.predicate); +} + +- (void)testProperties { + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil]; + + MGLFillExtrusionStyleLayer *layer = [[MGLFillExtrusionStyleLayer alloc] initWithIdentifier:@"layerID" source:source]; + XCTAssertNotEqual(layer.rawLayer, nullptr); + XCTAssertTrue(layer.rawLayer->is<mbgl::style::FillExtrusionLayer>()); + auto rawLayer = layer.rawLayer->as<mbgl::style::FillExtrusionLayer>(); + + MGLTransition transitionTest = MGLTransitionMake(5, 4); + + + // fill-extrusion-base + { + XCTAssertTrue(rawLayer->getFillExtrusionBase().isUndefined(), + @"fill-extrusion-base should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillExtrusionBase; + + MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.fillExtrusionBase = constantStyleValue; + mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getFillExtrusionBase(), propertyValue, + @"Setting fillExtrusionBase to a constant value should update fill-extrusion-base."); + XCTAssertEqualObjects(layer.fillExtrusionBase, constantStyleValue, + @"fillExtrusionBase should round-trip constant values."); + + MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.fillExtrusionBase = functionStyleValue; + + mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction<float> { intervalStops }; + + XCTAssertEqual(rawLayer->getFillExtrusionBase(), propertyValue, + @"Setting fillExtrusionBase to a camera function should update fill-extrusion-base."); + XCTAssertEqualObjects(layer.fillExtrusionBase, functionStyleValue, + @"fillExtrusionBase should round-trip camera functions."); + + functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.fillExtrusionBase = functionStyleValue; + + mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops }; + + XCTAssertEqual(rawLayer->getFillExtrusionBase(), propertyValue, + @"Setting fillExtrusionBase to a source function should update fill-extrusion-base."); + XCTAssertEqualObjects(layer.fillExtrusionBase, functionStyleValue, + @"fillExtrusionBase should round-trip source functions."); + + functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.fillExtrusionBase = functionStyleValue; + + std::map<float, float> innerStops { {18, 0xff} }; + mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 }; + + propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops }; + + XCTAssertEqual(rawLayer->getFillExtrusionBase(), propertyValue, + @"Setting fillExtrusionBase to a composite function should update fill-extrusion-base."); + XCTAssertEqualObjects(layer.fillExtrusionBase, functionStyleValue, + @"fillExtrusionBase should round-trip composite functions."); + + + layer.fillExtrusionBase = nil; + XCTAssertTrue(rawLayer->getFillExtrusionBase().isUndefined(), + @"Unsetting fillExtrusionBase should return fill-extrusion-base to the default value."); + XCTAssertEqualObjects(layer.fillExtrusionBase, defaultStyleValue, + @"fillExtrusionBase should return the default value after being unset."); + // Transition property test + layer.fillExtrusionBaseTransition = transitionTest; + auto toptions = rawLayer->getFillExtrusionBaseTransition(); + XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay); + XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration); + + MGLTransition fillExtrusionBaseTransition = layer.fillExtrusionBaseTransition; + XCTAssertEqual(fillExtrusionBaseTransition.delay, transitionTest.delay); + XCTAssertEqual(fillExtrusionBaseTransition.duration, transitionTest.duration); + } + + // fill-extrusion-color + { + XCTAssertTrue(rawLayer->getFillExtrusionColor().isUndefined(), + @"fill-extrusion-color should be unset initially."); + MGLStyleValue<MGLColor *> *defaultStyleValue = layer.fillExtrusionColor; + + MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]]; + layer.fillExtrusionColor = constantStyleValue; + mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } }; + XCTAssertEqual(rawLayer->getFillExtrusionColor(), propertyValue, + @"Setting fillExtrusionColor to a constant value should update fill-extrusion-color."); + XCTAssertEqualObjects(layer.fillExtrusionColor, constantStyleValue, + @"fillExtrusionColor should round-trip constant values."); + + MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.fillExtrusionColor = functionStyleValue; + + mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} }; + propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops }; + + XCTAssertEqual(rawLayer->getFillExtrusionColor(), propertyValue, + @"Setting fillExtrusionColor to a camera function should update fill-extrusion-color."); + XCTAssertEqualObjects(layer.fillExtrusionColor, functionStyleValue, + @"fillExtrusionColor should round-trip camera functions."); + + functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.fillExtrusionColor = functionStyleValue; + + mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops }; + + XCTAssertEqual(rawLayer->getFillExtrusionColor(), propertyValue, + @"Setting fillExtrusionColor to a source function should update fill-extrusion-color."); + XCTAssertEqualObjects(layer.fillExtrusionColor, functionStyleValue, + @"fillExtrusionColor should round-trip source functions."); + + functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.fillExtrusionColor = functionStyleValue; + + std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} }; + mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 }; + + propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops }; + + XCTAssertEqual(rawLayer->getFillExtrusionColor(), propertyValue, + @"Setting fillExtrusionColor to a composite function should update fill-extrusion-color."); + XCTAssertEqualObjects(layer.fillExtrusionColor, functionStyleValue, + @"fillExtrusionColor should round-trip composite functions."); + + + layer.fillExtrusionColor = nil; + XCTAssertTrue(rawLayer->getFillExtrusionColor().isUndefined(), + @"Unsetting fillExtrusionColor should return fill-extrusion-color to the default value."); + XCTAssertEqualObjects(layer.fillExtrusionColor, defaultStyleValue, + @"fillExtrusionColor should return the default value after being unset."); + // Transition property test + layer.fillExtrusionColorTransition = transitionTest; + auto toptions = rawLayer->getFillExtrusionColorTransition(); + XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay); + XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration); + + MGLTransition fillExtrusionColorTransition = layer.fillExtrusionColorTransition; + XCTAssertEqual(fillExtrusionColorTransition.delay, transitionTest.delay); + XCTAssertEqual(fillExtrusionColorTransition.duration, transitionTest.duration); + } + + // fill-extrusion-height + { + XCTAssertTrue(rawLayer->getFillExtrusionHeight().isUndefined(), + @"fill-extrusion-height should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillExtrusionHeight; + + MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.fillExtrusionHeight = constantStyleValue; + mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getFillExtrusionHeight(), propertyValue, + @"Setting fillExtrusionHeight to a constant value should update fill-extrusion-height."); + XCTAssertEqualObjects(layer.fillExtrusionHeight, constantStyleValue, + @"fillExtrusionHeight should round-trip constant values."); + + MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.fillExtrusionHeight = functionStyleValue; + + mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction<float> { intervalStops }; + + XCTAssertEqual(rawLayer->getFillExtrusionHeight(), propertyValue, + @"Setting fillExtrusionHeight to a camera function should update fill-extrusion-height."); + XCTAssertEqualObjects(layer.fillExtrusionHeight, functionStyleValue, + @"fillExtrusionHeight should round-trip camera functions."); + + functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil]; + layer.fillExtrusionHeight = functionStyleValue; + + mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 }; + propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops }; + + XCTAssertEqual(rawLayer->getFillExtrusionHeight(), propertyValue, + @"Setting fillExtrusionHeight to a source function should update fill-extrusion-height."); + XCTAssertEqualObjects(layer.fillExtrusionHeight, functionStyleValue, + @"fillExtrusionHeight should round-trip source functions."); + + functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil]; + layer.fillExtrusionHeight = functionStyleValue; + + std::map<float, float> innerStops { {18, 0xff} }; + mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 }; + + propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops }; + + XCTAssertEqual(rawLayer->getFillExtrusionHeight(), propertyValue, + @"Setting fillExtrusionHeight to a composite function should update fill-extrusion-height."); + XCTAssertEqualObjects(layer.fillExtrusionHeight, functionStyleValue, + @"fillExtrusionHeight should round-trip composite functions."); + + + layer.fillExtrusionHeight = nil; + XCTAssertTrue(rawLayer->getFillExtrusionHeight().isUndefined(), + @"Unsetting fillExtrusionHeight should return fill-extrusion-height to the default value."); + XCTAssertEqualObjects(layer.fillExtrusionHeight, defaultStyleValue, + @"fillExtrusionHeight should return the default value after being unset."); + // Transition property test + layer.fillExtrusionHeightTransition = transitionTest; + auto toptions = rawLayer->getFillExtrusionHeightTransition(); + XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay); + XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration); + + MGLTransition fillExtrusionHeightTransition = layer.fillExtrusionHeightTransition; + XCTAssertEqual(fillExtrusionHeightTransition.delay, transitionTest.delay); + XCTAssertEqual(fillExtrusionHeightTransition.duration, transitionTest.duration); + } + + // fill-extrusion-opacity + { + XCTAssertTrue(rawLayer->getFillExtrusionOpacity().isUndefined(), + @"fill-extrusion-opacity should be unset initially."); + MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillExtrusionOpacity; + + MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff]; + layer.fillExtrusionOpacity = constantStyleValue; + mbgl::style::PropertyValue<float> propertyValue = { 0xff }; + XCTAssertEqual(rawLayer->getFillExtrusionOpacity(), propertyValue, + @"Setting fillExtrusionOpacity to a constant value should update fill-extrusion-opacity."); + XCTAssertEqualObjects(layer.fillExtrusionOpacity, constantStyleValue, + @"fillExtrusionOpacity should round-trip constant values."); + + MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.fillExtrusionOpacity = functionStyleValue; + + mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} }; + propertyValue = mbgl::style::CameraFunction<float> { intervalStops }; + + XCTAssertEqual(rawLayer->getFillExtrusionOpacity(), propertyValue, + @"Setting fillExtrusionOpacity to a camera function should update fill-extrusion-opacity."); + XCTAssertEqualObjects(layer.fillExtrusionOpacity, functionStyleValue, + @"fillExtrusionOpacity should round-trip camera functions."); + + + + layer.fillExtrusionOpacity = nil; + XCTAssertTrue(rawLayer->getFillExtrusionOpacity().isUndefined(), + @"Unsetting fillExtrusionOpacity should return fill-extrusion-opacity to the default value."); + XCTAssertEqualObjects(layer.fillExtrusionOpacity, defaultStyleValue, + @"fillExtrusionOpacity should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.fillExtrusionOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); + functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.fillExtrusionOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); + // Transition property test + layer.fillExtrusionOpacityTransition = transitionTest; + auto toptions = rawLayer->getFillExtrusionOpacityTransition(); + XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay); + XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration); + + MGLTransition fillExtrusionOpacityTransition = layer.fillExtrusionOpacityTransition; + XCTAssertEqual(fillExtrusionOpacityTransition.delay, transitionTest.delay); + XCTAssertEqual(fillExtrusionOpacityTransition.duration, transitionTest.duration); + } + + // fill-extrusion-pattern + { + XCTAssertTrue(rawLayer->getFillExtrusionPattern().isUndefined(), + @"fill-extrusion-pattern should be unset initially."); + MGLStyleValue<NSString *> *defaultStyleValue = layer.fillExtrusionPattern; + + MGLStyleValue<NSString *> *constantStyleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Fill Extrusion Pattern"]; + layer.fillExtrusionPattern = constantStyleValue; + mbgl::style::PropertyValue<std::string> propertyValue = { "Fill Extrusion Pattern" }; + XCTAssertEqual(rawLayer->getFillExtrusionPattern(), propertyValue, + @"Setting fillExtrusionPattern to a constant value should update fill-extrusion-pattern."); + XCTAssertEqualObjects(layer.fillExtrusionPattern, constantStyleValue, + @"fillExtrusionPattern should round-trip constant values."); + + MGLStyleValue<NSString *> * functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.fillExtrusionPattern = functionStyleValue; + + mbgl::style::IntervalStops<std::string> intervalStops = { {{18, "Fill Extrusion Pattern"}} }; + propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops }; + + XCTAssertEqual(rawLayer->getFillExtrusionPattern(), propertyValue, + @"Setting fillExtrusionPattern to a camera function should update fill-extrusion-pattern."); + XCTAssertEqualObjects(layer.fillExtrusionPattern, functionStyleValue, + @"fillExtrusionPattern should round-trip camera functions."); + + + + layer.fillExtrusionPattern = nil; + XCTAssertTrue(rawLayer->getFillExtrusionPattern().isUndefined(), + @"Unsetting fillExtrusionPattern should return fill-extrusion-pattern to the default value."); + XCTAssertEqualObjects(layer.fillExtrusionPattern, defaultStyleValue, + @"fillExtrusionPattern should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.fillExtrusionPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); + functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.fillExtrusionPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); + // Transition property test + layer.fillExtrusionPatternTransition = transitionTest; + auto toptions = rawLayer->getFillExtrusionPatternTransition(); + XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay); + XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration); + + MGLTransition fillExtrusionPatternTransition = layer.fillExtrusionPatternTransition; + XCTAssertEqual(fillExtrusionPatternTransition.delay, transitionTest.delay); + XCTAssertEqual(fillExtrusionPatternTransition.duration, transitionTest.duration); + } + + // fill-extrusion-translate + { + XCTAssertTrue(rawLayer->getFillExtrusionTranslate().isUndefined(), + @"fill-extrusion-translate should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.fillExtrusionTranslation; + + MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue: +#if TARGET_OS_IPHONE + [NSValue valueWithCGVector:CGVectorMake(1, 1)] +#else + [NSValue valueWithMGLVector:CGVectorMake(1, -1)] +#endif + ]; + layer.fillExtrusionTranslation = constantStyleValue; + mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } }; + XCTAssertEqual(rawLayer->getFillExtrusionTranslate(), propertyValue, + @"Setting fillExtrusionTranslation to a constant value should update fill-extrusion-translate."); + XCTAssertEqualObjects(layer.fillExtrusionTranslation, constantStyleValue, + @"fillExtrusionTranslation should round-trip constant values."); + + MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.fillExtrusionTranslation = functionStyleValue; + + mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} }; + propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops }; + + XCTAssertEqual(rawLayer->getFillExtrusionTranslate(), propertyValue, + @"Setting fillExtrusionTranslation to a camera function should update fill-extrusion-translate."); + XCTAssertEqualObjects(layer.fillExtrusionTranslation, functionStyleValue, + @"fillExtrusionTranslation should round-trip camera functions."); + + + + layer.fillExtrusionTranslation = nil; + XCTAssertTrue(rawLayer->getFillExtrusionTranslate().isUndefined(), + @"Unsetting fillExtrusionTranslation should return fill-extrusion-translate to the default value."); + XCTAssertEqualObjects(layer.fillExtrusionTranslation, defaultStyleValue, + @"fillExtrusionTranslation should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.fillExtrusionTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); + functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.fillExtrusionTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); + } + + // fill-extrusion-translate-anchor + { + XCTAssertTrue(rawLayer->getFillExtrusionTranslateAnchor().isUndefined(), + @"fill-extrusion-translate-anchor should be unset initially."); + MGLStyleValue<NSValue *> *defaultStyleValue = layer.fillExtrusionTranslationAnchor; + + MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLFillExtrusionTranslationAnchor:MGLFillExtrusionTranslationAnchorViewport]]; + layer.fillExtrusionTranslationAnchor = constantStyleValue; + mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport }; + XCTAssertEqual(rawLayer->getFillExtrusionTranslateAnchor(), propertyValue, + @"Setting fillExtrusionTranslationAnchor to a constant value should update fill-extrusion-translate-anchor."); + XCTAssertEqualObjects(layer.fillExtrusionTranslationAnchor, constantStyleValue, + @"fillExtrusionTranslationAnchor should round-trip constant values."); + + MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil]; + layer.fillExtrusionTranslationAnchor = functionStyleValue; + + mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} }; + propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops }; + + XCTAssertEqual(rawLayer->getFillExtrusionTranslateAnchor(), propertyValue, + @"Setting fillExtrusionTranslationAnchor to a camera function should update fill-extrusion-translate-anchor."); + XCTAssertEqualObjects(layer.fillExtrusionTranslationAnchor, functionStyleValue, + @"fillExtrusionTranslationAnchor should round-trip camera functions."); + + + + layer.fillExtrusionTranslationAnchor = nil; + XCTAssertTrue(rawLayer->getFillExtrusionTranslateAnchor().isUndefined(), + @"Unsetting fillExtrusionTranslationAnchor should return fill-extrusion-translate-anchor to the default value."); + XCTAssertEqualObjects(layer.fillExtrusionTranslationAnchor, defaultStyleValue, + @"fillExtrusionTranslationAnchor should return the default value after being unset."); + + functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.fillExtrusionTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); + functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil]; + XCTAssertThrowsSpecificNamed(layer.fillExtrusionTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it"); + } +} + +- (void)testPropertyNames { + [self testPropertyName:@"fill-extrusion-base" isBoolean:NO]; + [self testPropertyName:@"fill-extrusion-color" isBoolean:NO]; + [self testPropertyName:@"fill-extrusion-height" isBoolean:NO]; + [self testPropertyName:@"fill-extrusion-opacity" isBoolean:NO]; + [self testPropertyName:@"fill-extrusion-pattern" isBoolean:NO]; + [self testPropertyName:@"fill-extrusion-translation" isBoolean:NO]; + [self testPropertyName:@"fill-extrusion-translation-anchor" isBoolean:NO]; +} + +- (void)testValueAdditions { + XCTAssertEqual([NSValue valueWithMGLFillExtrusionTranslationAnchor:MGLFillExtrusionTranslationAnchorMap].MGLFillExtrusionTranslationAnchorValue, MGLFillExtrusionTranslationAnchorMap); + XCTAssertEqual([NSValue valueWithMGLFillExtrusionTranslationAnchor:MGLFillExtrusionTranslationAnchorViewport].MGLFillExtrusionTranslationAnchorValue, MGLFillExtrusionTranslationAnchorViewport); +} + +@end diff --git a/platform/darwin/test/MGLStyleLayerTests.mm.ejs b/platform/darwin/test/MGLStyleLayerTests.mm.ejs index a405ae58c4..5fdfc3d44e 100644 --- a/platform/darwin/test/MGLStyleLayerTests.mm.ejs +++ b/platform/darwin/test/MGLStyleLayerTests.mm.ejs @@ -11,7 +11,7 @@ #import "MGLStyleLayer_Private.h" -#include <mbgl/style/layers/<%- type %>_layer.hpp> +#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp> #include <mbgl/style/transition_options.hpp> @interface MGL<%- camelize(type) %>LayerTests : MGLStyleLayerTests |