Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
wip: implement MGLStyleFunction initializers
Browse files Browse the repository at this point in the history
  • Loading branch information
boundsj committed Feb 6, 2017
1 parent 646b0d3 commit 406e647
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 23 deletions.
56 changes: 55 additions & 1 deletion platform/darwin/src/MGLStyleValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,59 @@ MGL_EXPORT
MGL_EXPORT
@interface MGLStyleFunction<T> : MGLStyleValue<T>

#pragma mark Creating a Style Function

/**
Creates and returns an `MGLStyleFunction` object representing a camera function.
If the function is set as a style layer property value, it will be interpreted
as a camera function with a linear interpolation curve.
@note Do not create instances of `MGLStyleFunction` unless it is required for
backwards compatiblity with your application code. You should create and use
instances of `MGLCameraStyleFunction` to specify how properties will
be visualized at different zoom levels.
@param stops A dictionary associating zoom levels with style values.
@return An `MGLStyleFunction` object with the given stops.
*/
+ (instancetype)functionWithStops:(NSDictionary<id, MGLStyleValue<T> *> *)stops __attribute__((deprecated("Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]")));

/**
Creates and returns an `MGLStyleFunction` object representing a camera function.
If the function is set as a style layer property value, it will be interpreted
as a camera function with an interpolation curve controlled by the provided
interpolation base.
@note Do not create instances of `MGLStyleFunction` unless it is required for
backwards compatiblity with your application code. You should create and use
instances of `MGLCameraStyleFunction` to specify how properties will
be visualized at different zoom levels.
@param interpolationBase The exponential base of the interpolation curve.
@param stops A dictionary associating zoom levels with style values.
@return An `MGLStyleFunction` object with the given interpolation base and stops.
*/
+ (instancetype)functionWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary<id, MGLStyleValue<T> *> *)stops __attribute__((deprecated("Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]")));

#pragma mark Initializing a Style Function

/**
Returns an `MGLStyleFunction` object representing a camera function. If the
function is set as a style layer property value, it will be interpreted
as a camera function with an interpolation curve controlled by the provided
interpolation base.
@note Do not create instances of `MGLStyleFunction` unless it is required for
backwards compatiblity with your application code. You should create and use
instances of `MGLCameraStyleFunction` to specify how properties will
be visualized at different zoom levels.
@param interpolationBase The exponential base of the interpolation curve.
@param stops A dictionary associating zoom levels with style values.
@return An `MGLStyleFunction` object with the given interpolation base and stops.
*/
- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary<id, MGLStyleValue<T> *> *)stops NS_DESIGNATED_INITIALIZER;

#pragma mark Accessing the Parameters of a Function

/**
Expand All @@ -207,7 +260,8 @@ MGL_EXPORT
@note This property specifies the exponential base of the interpolation curve
of `MGLCameraStyleFunction` and `MGLSourceStyleFunction` functions that use
a `MGLInterpolationModeExponential` `interpolationMode`.
a `MGLInterpolationModeExponential` `interpolationMode`. Otherwise, it is
ignored.
*/
@property (nonatomic) CGFloat interpolationBase;

Expand Down
65 changes: 48 additions & 17 deletions platform/darwin/src/MGLStyleValue.mm
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,45 @@ - (NSUInteger)hash {

@implementation MGLStyleFunction

+ (instancetype)functionWithStops:(NSDictionary *)stops {
return [[self alloc] initWithInterpolationBase:1.0 stops:stops];
}

+ (instancetype)functionWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
return [[self alloc] initWithInterpolationBase:interpolationBase stops:stops];
}

- (instancetype)init {
return [self initWithInterpolationBase:1.0 stops:@{}];
}

- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
if (self = [super init]) {
self.interpolationBase = interpolationBase;
self.stops = stops;
}
return self;
}

- (NSString *)description {
return [NSString stringWithFormat:@"<%@: %p, \
stops = %@, \
interpolationBase = %f>",
NSStringFromClass([self class]), (void *)self,
self.stops,
self.interpolationBase];
}

- (BOOL)isEqual:(MGLStyleFunction *)other {
return ([other isKindOfClass:[self class]]
&& [other.stops isEqualToDictionary:self.stops]
&& other.interpolationBase == self.interpolationBase);
}

- (NSUInteger)hash {
return self.stops.hash + self.interpolationBase;
}

@end

@implementation MGLCameraStyleFunction
Expand All @@ -74,8 +113,8 @@ + (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolatio
return [[self alloc] initWithInterpolationMode:interpolationMode stops:stops options:options];
}

- (instancetype)init {
return [self initWithInterpolationMode:MGLInterpolationModeExponential stops:@{} options:nil];
- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
return [self initWithInterpolationMode:MGLInterpolationModeExponential stops:stops options:@{MGLStyleFunctionOptionInterpolationBase: @(interpolationBase)}];
}

- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops options:(NSDictionary *)options {
Expand All @@ -85,10 +124,8 @@ - (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMod
return {};
}

if (self == [super init]) {
if (self == [super initWithInterpolationBase:1.0 stops:stops]) {
self.interpolationMode = interpolationMode;
self.stops = stops;
self.interpolationBase = 1.0;

if ([options.allKeys containsObject:MGLStyleFunctionOptionInterpolationBase]) {
if ([options[MGLStyleFunctionOptionInterpolationBase] isKindOfClass:[NSNumber class]]) {
Expand Down Expand Up @@ -134,16 +171,13 @@ + (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolatio
return [[self alloc] initWithInterpolationMode:interpolationMode stops:stops attributeName:attributeName options:options];
}

- (instancetype)init {
return [self initWithInterpolationMode:MGLInterpolationModeExponential stops:nil attributeName:@"" options:nil];
- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
return [self initWithInterpolationMode:MGLInterpolationModeExponential stops:stops attributeName:@"" options:@{MGLStyleFunctionOptionInterpolationBase: @(interpolationBase)}];
}

- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
if (self == [super init]) {
if (self == [super initWithInterpolationBase:1.0 stops:stops]) {
self.interpolationMode = interpolationMode;
self.stops = stops;
self.interpolationBase = 1.0;

_attributeName = attributeName;

if ([options.allKeys containsObject:MGLStyleFunctionOptionDefaultValue]) {
Expand Down Expand Up @@ -206,16 +240,13 @@ + (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolatio
return [[self alloc] initWithInterpolationMode:interpolationMode stops:stops attributeName:attributeName options:options];
}

- (instancetype)init {
return [self initWithInterpolationMode:MGLInterpolationModeExponential stops:@{} attributeName:@"" options:nil];
- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
return [self initWithInterpolationMode:MGLInterpolationModeExponential stops:stops attributeName:@"" options:@{MGLStyleFunctionOptionInterpolationBase: @(interpolationBase)}];
}

- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
if (self == [super init]) {
if (self == [super initWithInterpolationBase:1.0 stops:stops]) {
self.interpolationMode = interpolationMode;
self.stops = stops;
self.interpolationBase = 1.0;

_attributeName = attributeName;

if ([options.allKeys containsObject:MGLStyleFunctionOptionDefaultValue]) {
Expand Down
19 changes: 14 additions & 5 deletions platform/darwin/src/MGLStyleValue_Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ class MGLStyleValueTransformer {
// a deprecated MGLStyleValue method (that used to create an MGLStyleFunction) to create a function
// for properties that are piecewise-constant (i.e. enum, bool, string)
return toMBGLIntervalCameraFunction(cameraStyleFunction);
} else if ([value isMemberOfClass:[MGLStyleFunction class]]) {
MGLStyleFunction<ObjCType> *styleFunction = (MGLStyleFunction<ObjCType> *)value;
return toMBGLIntervalCameraFunction(styleFunction);
} else if (value) {
[NSException raise:@"MGLAbstractClassException" format:
@"The style value %@ cannot be applied to the style. "
Expand All @@ -81,6 +84,9 @@ class MGLStyleValueTransformer {

if ([value isKindOfClass:[MGLStyleConstantValue class]]) {
return toMBGLConstantValue((MGLStyleConstantValue<ObjCType> *)value);
} else if ([value isMemberOfClass:[MGLStyleFunction class]]) {
MGLStyleFunction<ObjCType> *styleFunction = (MGLStyleFunction<ObjCType> *)value;
return toMBGLExponentialCameraFunction(styleFunction);
} else if ([value isKindOfClass:[MGLCameraStyleFunction class]]) {
MGLCameraStyleFunction<ObjCType> *cameraStyleFunction = (MGLCameraStyleFunction<ObjCType> *)value;
switch (cameraStyleFunction.interpolationMode) {
Expand Down Expand Up @@ -247,6 +253,9 @@ class MGLStyleValueTransformer {
return {};
}
return {};
} else if ([value isMemberOfClass:[MGLStyleFunction class]]) {
MGLStyleFunction<ObjCType> *styleFunction = (MGLStyleFunction<ObjCType> *)value;
return toMBGLExponentialCameraFunction(styleFunction);
} else if (value) {
[NSException raise:@"MGLAbstractClassException" format:
@"The style value %@ cannot be applied to the style. "
Expand Down Expand Up @@ -308,25 +317,25 @@ class MGLStyleValueTransformer {
return mbglValue;
}

mbgl::style::CameraFunction<MBGLType> toMBGLExponentialCameraFunction(MGLCameraStyleFunction<ObjCType> *cameraStyleFunction) {
mbgl::style::CameraFunction<MBGLType> toMBGLExponentialCameraFunction(MGLStyleFunction<ObjCType> *styleFunction) {
__block std::map<float, MBGLType> stops = {};
[cameraStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue<ObjCType> * _Nonnull stopValue, BOOL * _Nonnull stop) {
[styleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue<ObjCType> * _Nonnull stopValue, BOOL * _Nonnull stop) {
NSCAssert([stopValue isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues");
auto mbglStopValue = toPropertyValue(stopValue);
NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
stops[zoomKey.floatValue] = mbglStopValue.asConstant();
}];

// Camera function with Exponential stops
mbgl::style::ExponentialStops<MBGLType> exponentialStops = {stops, (float)cameraStyleFunction.interpolationBase};
mbgl::style::ExponentialStops<MBGLType> exponentialStops = {stops, (float)styleFunction.interpolationBase};
mbgl::style::CameraFunction<MBGLType> cameraFunction = {exponentialStops};

return cameraFunction;
}

mbgl::style::CameraFunction<MBGLType> toMBGLIntervalCameraFunction(MGLCameraStyleFunction<ObjCType> *cameraStyleFunction) {
mbgl::style::CameraFunction<MBGLType> toMBGLIntervalCameraFunction(MGLStyleFunction<ObjCType> *styleFunction) {
__block std::map<float, MBGLType> stops = {};
[cameraStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue<ObjCType> * _Nonnull stopValue, BOOL * _Nonnull stop) {
[styleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue<ObjCType> * _Nonnull stopValue, BOOL * _Nonnull stop) {
NSCAssert([stopValue isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues");
auto mbglStopValue = toPropertyValue(stopValue);
NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
Expand Down
61 changes: 61 additions & 0 deletions platform/darwin/test/MGLStyleValueTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ extension MGLStyleValueTests {
func testDeprecatedFunctions() {
let shapeSource = MGLShapeSource(identifier: "test", shape: nil, options: nil)
let symbolStyleLayer = MGLSymbolStyleLayer(identifier: "symbolLayer", source: shapeSource)
let circleStyleLayer = MGLCircleStyleLayer(identifier: "circleLayer", source: shapeSource)

// deprecated function, stops with float values
let iconHaloBlurStyleValue = MGLStyleValue<NSNumber>(interpolationBase: 1.0, stops: [1: MGLStyleValue(rawValue: 0),
Expand All @@ -63,6 +64,66 @@ extension MGLStyleValueTests {
options: nil
)
XCTAssertEqual(symbolStyleLayer.iconAllowsOverlap, expectedIconAllowsOverlapStyleValue)

///
// creating and using MGLStyleFunctions directly
///

let circleRadiusStops: [NSNumber: MGLStyleValue<NSNumber>] = [
0: MGLStyleValue(rawValue: 10),
20: MGLStyleValue(rawValue: 5)
]
let circleRadiusFunction = MGLStyleFunction<NSNumber>(
interpolationBase: 1.0,
stops: circleRadiusStops
)
circleStyleLayer.circleRadius = circleRadiusFunction
let expectedCircleRadiusFunction = MGLStyleValue<NSNumber>(
interpolationMode: .exponential,
cameraStops:
circleRadiusStops,
options: nil
)
// setting a data driven property to an MGLStyleFunction should return an exponential camera function
XCTAssertEqual(circleStyleLayer.circleRadius, expectedCircleRadiusFunction)

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<NSValue>(rawValue: circleTranslationValueOne),
10: MGLStyleValue<NSValue>(rawValue: circleTranslationValueTwo)
]
let circleTranslationFunction = MGLStyleFunction(
interpolationBase: 1.0,
stops: circleTranslationStops
)
circleStyleLayer.circleTranslation = circleTranslationFunction
let expectedCircleTranslationFunction = MGLStyleValue<NSValue>(
interpolationMode: .exponential,
cameraStops: circleTranslationStops,
options: nil
)
// setting a non-data driven, interpolatable property to an MGLStyleFunction should return an exponential camera function
XCTAssertEqual(circleStyleLayer.circleTranslation, expectedCircleTranslationFunction)

let iconOptionalStops: [NSNumber: MGLStyleValue<NSNumber>] = [
0: MGLStyleValue(rawValue: false),
20: MGLStyleValue(rawValue: true)
]
let iconOptionalFunction = MGLStyleFunction(
interpolationBase: 1.0,
stops: iconOptionalStops
)
symbolStyleLayer.iconOptional = iconOptionalFunction
let expectedIconOptionalFunction = MGLStyleValue(
interpolationMode: .interval,
cameraStops: iconOptionalStops,
options: nil
)
XCTAssertEqual(symbolStyleLayer.iconOptional, expectedIconOptionalFunction)
}

func testFunctionsWithNonDataDrivenProperties() {
Expand Down

0 comments on commit 406e647

Please sign in to comment.