diff options
Diffstat (limited to 'platform/darwin/src/MGLStyleValue_Private.h')
-rw-r--r-- | platform/darwin/src/MGLStyleValue_Private.h | 661 |
1 files changed, 569 insertions, 92 deletions
diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h index 2c3de3fb74..3a5ce8d474 100644 --- a/platform/darwin/src/MGLStyleValue_Private.h +++ b/platform/darwin/src/MGLStyleValue_Private.h @@ -4,64 +4,108 @@ #import "NSValue+MGLStyleAttributeAdditions.h" #import "MGLTypes.h" + +#import "MGLConversion.h" +#include <mbgl/style/conversion/data_driven_property_value.hpp> +#include <mbgl/style/conversion.hpp> + #import <mbgl/util/enum.hpp> +#include <mbgl/style/data_driven_property_value.hpp> + +#include <mbgl/util/interpolate.hpp> + #if TARGET_OS_IPHONE #import "UIColor+MGLAdditions.h" #else #import "NSColor+MGLAdditions.h" #endif -#include <array> - template <typename MBGLType, typename ObjCType, typename MBGLElement = MBGLType, typename ObjCEnum = ObjCType> class MGLStyleValueTransformer { public: - + + // Convert an mbgl property value into an mgl style value MGLStyleValue<ObjCType> *toStyleValue(const mbgl::style::PropertyValue<MBGLType> &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<ObjCType> *toDataDrivenStyleValue(const mbgl::style::DataDrivenPropertyValue<MBGLType> &mbglValue) { + PropertyValueEvaluator evaluator; + return mbglValue.evaluate(evaluator); + } + + // Convert an mbgl property value containing an enum into an mgl style value template <typename MBGLEnum = MBGLType, class = typename std::enable_if<std::is_enum<MBGLEnum>::value>::type, typename MGLEnum = ObjCEnum, class = typename std::enable_if<std::is_enum<MGLEnum>::value>::type> MGLStyleValue<ObjCType> *toEnumStyleValue(const mbgl::style::PropertyValue<MBGLEnum> &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); - } - return [MGLStyleFunction<NSValue *> functionWithInterpolationBase:mbglValue.asFunction().getBase() stops:stops]; + EnumPropertyValueEvaluator<MBGLEnum, ObjCEnum> evaluator; + return mbglValue.evaluate(evaluator); + } + + // Convert an mgl style value into a non interpolatable (camera with interval stops) mbgl property value + mbgl::style::PropertyValue<MBGLType> toPropertyValue(MGLStyleValue<ObjCType> *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<ObjCType> *)value); + } else if ([value isKindOfClass:[MGLCameraStyleFunction class]]) { + MGLCameraStyleFunction<ObjCType> *cameraStyleFunction = (MGLCameraStyleFunction<ObjCType> *)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 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. " + @"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<MBGLType> toPropertyValue(MGLStyleValue<ObjCType> *value) { + // Convert an mgl style value into a non interpolatable (camera with exponential or interval stops) mbgl property value + mbgl::style::PropertyValue<MBGLType> toInterpolatablePropertyValue(MGLStyleValue<ObjCType> *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]]) { - MBGLType mbglValue; - getMBGLValue([(MGLStyleConstantValue<ObjCType> *)value rawValue], mbglValue); - return mbglValue; - } else if ([value isKindOfClass:[MGLStyleFunction class]]) { - MGLStyleFunction<ObjCType> *function = (MGLStyleFunction<ObjCType> *)value; - __block std::vector<std::pair<float, MBGLType>> mbglStops; - [function.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"); - mbglStops.emplace_back(zoomKey.floatValue, mbglStopValue.asConstant()); - }]; - return mbgl::style::Function<MBGLType>({{mbglStops}}, function.interpolationBase); + 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) { + 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 {}; } else if (value) { [NSException raise:@"MGLAbstractClassException" format: @"The style value %@ cannot be applied to the style. " @@ -73,25 +117,51 @@ public: } } + // Convert an mgl style value into a mbgl data driven property value + mbgl::style::DataDrivenPropertyValue<MBGLType> toDataDrivenPropertyValue(MGLStyleValue<ObjCType> *value) { + if ([value isKindOfClass:[MGLStyleConstantValue class]]) { + return toMBGLConstantValue((MGLStyleConstantValue<ObjCType> *)value); + } else if ([value isKindOfClass:[MGLStyleFunction class]]) { + auto rawValue = toRawStyleSpecValue((MGLStyleFunction<ObjCType> *) value); + auto result = mbgl::style::conversion::convert<mbgl::style::DataDrivenPropertyValue<MBGLType>>(rawValue); + NSCAssert(result, @(result.error().message.c_str())); + return *result; + } else { + return {}; + } + } + + // Convert an mgl style value containing an enum into a mbgl property value containing an enum template <typename MBGLEnum = MBGLType, class = typename std::enable_if<std::is_enum<MBGLEnum>::value>::type, typename MGLEnum = ObjCEnum, class = typename std::enable_if<std::is_enum<MGLEnum>::value>::type> mbgl::style::PropertyValue<MBGLEnum> toEnumPropertyValue(MGLStyleValue<ObjCType> *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<ObjCType> *)value rawValue], mbglValue); return mbglValue; - } else if ([value isKindOfClass:[MGLStyleFunction class]]) { - MGLStyleFunction<NSValue *> *function = (MGLStyleFunction<NSValue *> *)value; - __block std::vector<std::pair<float, MBGLEnum>> mbglStops; - [function.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue<NSValue *> * _Nonnull stopValue, BOOL * _Nonnull stop) { + } else if ([value isKindOfClass:[MGLCameraStyleFunction class]]) { + MGLCameraStyleFunction<NSValue *> *cameraStyleFunction = (MGLCameraStyleFunction<NSValue *> *)value; + __block std::map<float, MBGLType> stops = {}; + [cameraStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue<NSValue *> * _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<MBGLEnum>({{mbglStops}}, function.interpolationBase); + + // Enumerations can only ever use interval stops. + mbgl::style::IntervalStops<MBGLType> intervalStops = {stops}; + + mbgl::style::CameraFunction<MBGLType> cameraFunction = {intervalStops}; + return cameraFunction; } else if (value) { [NSException raise:@"MGLAbstractClassException" format: @"The style value %@ cannot be applied to the style. " @@ -103,95 +173,239 @@ public: } } -private: +private: // Private utilities for converting from mgl to mbgl values - MGLStyleConstantValue<ObjCType> *toStyleConstantValue(const MBGLType mbglValue) { - auto rawValue = toMGLRawStyleValue(mbglValue); - return [MGLStyleConstantValue<ObjCType> valueWithRawValue:rawValue]; + MBGLType toMBGLConstantValue(MGLStyleConstantValue<ObjCType> *value) { + MBGLType mbglValue; + getMBGLValue(value.rawValue, mbglValue); + return mbglValue; } - MGLStyleFunction<ObjCType> *toStyleFunction(const mbgl::style::Function<MBGLType> &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]; + /** + As hack to allow converting enum => string values, we accept a second, dummy parameter in + the toRawStyleSpecValue() methods for converting 'atomic' (non-style-function) values. + This allows us to use `std::enable_if` to test (at compile time) whether or not MBGLType is an Enum. + */ + template <typename MBGLEnum = MBGLType, + class = typename std::enable_if<!std::is_enum<MBGLEnum>::value>::type, + typename MGLEnum = ObjCEnum, + class = typename std::enable_if<!std::is_enum<MGLEnum>::value>::type> + NSObject* toRawStyleSpecValue(NSObject *rawMGLValue, MBGLEnum &mbglValue) { + if ([rawMGLValue isKindOfClass:[NSValue class]]) { + const auto rawNSValue = (NSValue *)rawMGLValue; + if (strcmp([rawNSValue objCType], @encode(CGVector)) == 0) { + // offset [x, y] + std::array<float, 2> mglValue = rawNSValue.mgl_offsetArrayValue; + return [NSArray arrayWithObjects:@(mglValue[0]), @(mglValue[1]), nil]; + } } - return [MGLStyleFunction<ObjCType> functionWithInterpolationBase:mbglFunction.getBase() stops:stops]; + // noop pass-through plain NSObject-based items + return rawMGLValue; } - + template <typename MBGLEnum = MBGLType, - class = typename std::enable_if<std::is_enum<MBGLEnum>::value>::type, - typename MGLEnum = ObjCEnum, - class = typename std::enable_if<std::is_enum<MGLEnum>::value>::type> - MGLStyleConstantValue<ObjCType> *toEnumStyleConstantValue(const MBGLEnum mbglValue) { - auto str = mbgl::Enum<MBGLEnum>::toString(mbglValue); - MGLEnum mglType = *mbgl::Enum<MGLEnum>::toEnum(str); - return [MGLStyleConstantValue<ObjCType> valueWithRawValue:[NSValue value:&mglType withObjCType:@encode(MGLEnum)]]; - } - - NSNumber *toMGLRawStyleValue(const bool mbglStopValue) { - return @(mbglStopValue); + class = typename std::enable_if<std::is_enum<MBGLEnum>::value>::type, + typename MGLEnum = ObjCEnum, + class = typename std::enable_if<std::is_enum<MGLEnum>::value>::type> + NSString* toRawStyleSpecValue(ObjCType rawValue, MBGLEnum &mbglValue) { + MGLEnum mglEnum; + [rawValue getValue:&mglEnum]; + return @(mbgl::Enum<MGLEnum>::toString(mglEnum)); } - NSNumber *toMGLRawStyleValue(const float mbglStopValue) { - return @(mbglStopValue); + NSObject* toRawStyleSpecValue(MGLColor *color, MBGLType &mbglValue) { + return @(color.mgl_color.stringify().c_str()); } + - NSString *toMGLRawStyleValue(const std::string &mbglStopValue) { - return @(mbglStopValue.c_str()); + NSObject* toRawStyleSpecValue(MGLStyleFunction<ObjCType>* styleFunction) { + NSMutableDictionary * rawFunction = [NSMutableDictionary new]; + // interpolationMode => type + switch (styleFunction.interpolationMode) { + case MGLInterpolationModeExponential: + rawFunction[@"type"] = @"exponential"; + break; + case MGLInterpolationModeInterval: + rawFunction[@"type"] = @"interval"; + break; + case MGLInterpolationModeCategorical: + rawFunction[@"type"] = @"categorical"; + break; + case MGLInterpolationModeIdentity: + rawFunction[@"type"] = @"identity"; + break; + } + + // interpolationBase => base + if (styleFunction.interpolationBase) { + rawFunction[@"base"] = @(styleFunction.interpolationBase); + } + + // stops and default value + if ([styleFunction isKindOfClass:[MGLCameraStyleFunction class]]) { + // zoom-only function (no default value) + __block NSMutableArray *stops = [[NSMutableArray alloc] init]; + [styleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleConstantValue<ObjCType> * _Nonnull outputValue, BOOL * _Nonnull stop) { + MBGLType dummyMbglValue; + NSArray *rawStop = @[zoomKey, toRawStyleSpecValue([outputValue rawValue], dummyMbglValue)]; + [stops addObject:rawStop]; + }]; + rawFunction[@"stops"] = stops; + + } else if ([styleFunction isKindOfClass:[MGLSourceStyleFunction class]]) { + auto sourceStyleFunction = (MGLSourceStyleFunction<ObjCType> *)styleFunction; + rawFunction[@"property"] = sourceStyleFunction.attributeName; + // property-only function + __block NSMutableArray *stops = [[NSMutableArray alloc] init]; + [styleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSObject * _Nonnull propertyKey, MGLStyleConstantValue<ObjCType> * _Nonnull outputValue, BOOL * _Nonnull stop) { + MBGLType dummyMbglValue; + NSArray *rawStop = @[propertyKey, toRawStyleSpecValue([outputValue rawValue], dummyMbglValue)]; + [stops addObject:rawStop]; + }]; + rawFunction[@"stops"] = stops; + + // defaultValue => default + if (sourceStyleFunction.defaultValue) { + NSCAssert([sourceStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant"); + MBGLType dummyMbglValue; + rawFunction[@"default"] = toRawStyleSpecValue([(MGLStyleConstantValue<ObjCType> *)sourceStyleFunction.defaultValue rawValue], dummyMbglValue); + } + } else if ([styleFunction isKindOfClass:[MGLCompositeStyleFunction class]]) { + // zoom-and-property function + auto compositeStyleFunction = (MGLCompositeStyleFunction<ObjCType> *)styleFunction; + rawFunction[@"property"] = compositeStyleFunction.attributeName; + + __block NSMutableArray *stops = [[NSMutableArray alloc] init]; + [compositeStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, NSDictionary * _Nonnull stopValue, BOOL * _Nonnull stop) { + for (NSObject *valueKey in stopValue.allKeys) { + NSDictionary *stopKey = @{ + @"zoom": zoomKey, + @"value": valueKey + }; + MGLStyleConstantValue<ObjCType> *outputValue = stopValue[valueKey]; + NSCAssert([outputValue isKindOfClass:[MGLStyleConstantValue<ObjCType> class]], @"Stop outputs should be MGLStyleConstantValues"); + MBGLType dummyMbglValue; + NSArray *rawStop = @[stopKey, toRawStyleSpecValue([outputValue rawValue], dummyMbglValue)]; + [stops addObject:rawStop]; + } + }]; + rawFunction[@"stops"] = stops; + + // defaultValue => default + if (compositeStyleFunction.defaultValue) { + NSCAssert([compositeStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant"); + MBGLType dummyMbglValue; + rawFunction[@"default"] = toRawStyleSpecValue([(MGLStyleConstantValue<ObjCType> *)compositeStyleFunction.defaultValue rawValue], dummyMbglValue); + } + } + + return rawFunction; } - - // Offsets - NSValue *toMGLRawStyleValue(const std::array<float, 2> &mbglStopValue) { - return [NSValue mgl_valueWithOffsetArray:mbglStopValue]; + + mbgl::style::CameraFunction<MBGLType> toMBGLExponentialCameraFunction(MGLStyleFunction<ObjCType> *styleFunction) { + __block std::map<float, MBGLType> stops = {}; + [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)styleFunction.interpolationBase}; + mbgl::style::CameraFunction<MBGLType> cameraFunction = {exponentialStops}; + + return cameraFunction; } - - // Padding - NSValue *toMGLRawStyleValue(const std::array<float, 4> &mbglStopValue) { - return [NSValue mgl_valueWithPaddingArray:mbglStopValue]; + + mbgl::style::CameraFunction<MBGLType> toMBGLIntervalCameraFunction(MGLStyleFunction<ObjCType> *styleFunction) { + __block std::map<float, MBGLType> stops = {}; + [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 Interval stops + mbgl::style::IntervalStops<MBGLType> intervalStops = {stops}; + mbgl::style::CameraFunction<MBGLType> cameraFunction = {intervalStops}; + + return cameraFunction; } - - MGLColor *toMGLRawStyleValue(const mbgl::Color mbglStopValue) { - return [MGLColor mgl_colorWithColor:mbglStopValue]; + + mbgl::style::SourceFunction<MBGLType> toMBGLCategoricalSourceFunction(MGLSourceStyleFunction<ObjCType> *sourceStyleFunction) { + __block std::map<mbgl::style::CategoricalValue, MBGLType> stops = {}; + [sourceStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(id categoryKey, MGLStyleValue<ObjCType> *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<MBGLType> categoricalStops = {stops}; + mbgl::style::SourceFunction<MBGLType> sourceFunction = {sourceStyleFunction.attributeName.UTF8String, categoricalStops}; + setDefaultMBGLValue(sourceStyleFunction, sourceFunction); + return sourceFunction; } - - ObjCType toMGLRawStyleValue(const std::vector<MBGLElement> &mbglStopValue) { - NSMutableArray *array = [NSMutableArray arrayWithCapacity:mbglStopValue.size()]; - for (const auto &mbglElement: mbglStopValue) { - [array addObject:toMGLRawStyleValue(mbglElement)]; + + void setDefaultMBGLValue(MGLSourceStyleFunction<ObjCType> *sourceStyleFunction, mbgl::style::SourceFunction<MBGLType> &sourceFunction) { + if (sourceStyleFunction.defaultValue) { + NSCAssert([sourceStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant"); + MBGLType mbglValue; + id mglValue = [(MGLStyleConstantValue<ObjCType> *)sourceStyleFunction.defaultValue rawValue]; + getMBGLValue(mglValue, mbglValue); + sourceFunction.defaultValue = mbglValue; } - return array; } -private: - + // 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; } - + // Offsets void getMBGLValue(NSValue *rawValue, std::array<float, 2> &mbglValue) { mbglValue = rawValue.mgl_offsetArrayValue; } - + // Padding void getMBGLValue(NSValue *rawValue, std::array<float, 4> &mbglValue) { mbglValue = rawValue.mgl_paddingArrayValue; } - + + // Color void getMBGLValue(MGLColor *rawValue, mbgl::Color &mbglValue) { mbglValue = rawValue.mgl_color; } - + + // Array void getMBGLValue(ObjCType rawValue, std::vector<MBGLElement> &mbglValue) { mbglValue.reserve(rawValue.count); for (id obj in rawValue) { @@ -212,4 +426,267 @@ private: auto str = mbgl::Enum<MGLEnum>::toString(mglEnum); mbglValue = *mbgl::Enum<MBGLEnum>::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<float, 2> &mbglStopValue) { + return [NSValue mgl_valueWithOffsetArray:mbglStopValue]; + } + + // Padding + static NSValue *toMGLRawStyleValue(const std::array<float, 4> &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<MBGLElement> &mbglStopValue) { + NSMutableArray *array = [NSMutableArray arrayWithCapacity:mbglStopValue.size()]; + for (const auto &mbglElement: mbglStopValue) { + [array addObject:toMGLRawStyleValue(mbglElement)]; + } + return array; + } + + // Enumerations + template <typename MBGLEnum = MBGLType, typename MGLEnum = ObjCEnum> + static NSValue *toMGLRawStyleValue(const MBGLEnum &value) { + auto str = mbgl::Enum<MBGLEnum>::toString(value); + MGLEnum mglType = *mbgl::Enum<MGLEnum>::toEnum(str); + return [NSValue value:&mglType withObjCType:@encode(MGLEnum)]; + } + + // Converts mbgl stops to an equivilent NSDictionary for mgl + static NSMutableDictionary *toConvertedStops(const std::map<float, MBGLType> &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 <typename MBGLEnum = MBGLType, typename MGLEnum = ObjCEnum> + class EnumPropertyValueEvaluator { + public: + id operator()(const mbgl::style::Undefined) const { + return nil; + } + + id operator()(const MBGLEnum &value) const { + auto str = mbgl::Enum<MBGLEnum>::toString(value); + MGLEnum mglType = *mbgl::Enum<MGLEnum>::toEnum(str); + return [MGLStyleConstantValue<ObjCType> valueWithRawValue:[NSValue value:&mglType withObjCType:@encode(MGLEnum)]]; + } + + id operator()(const mbgl::style::CameraFunction<MBGLEnum> &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<MBGLType> &mbglStops) { + return [MGLCameraStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential + stops:toConvertedStops(mbglStops.stops) + options:@{MGLStyleFunctionOptionInterpolationBase: @(mbglStops.base)}]; + } + + id operator()(const mbgl::style::IntervalStops<MBGLType> &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<MBGLType> &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<MBGLType> &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<MBGLType> &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<MBGLType> &mbglStops) { + MGLSourceStyleFunction *sourceFunction = [MGLSourceStyleFunction functionWithInterpolationMode:MGLInterpolationModeIdentity + stops:nil + attributeName:@(mbglFunction.property.c_str()) options:nil]; + if (mbglFunction.defaultValue) { + sourceFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)]; + } + return sourceFunction; + } + + const mbgl::style::SourceFunction<MBGLType> &mbglFunction; + }; + + // Converts a composite function and all possible mbgl stops into an equivilant mgl style value + class CompositeFunctionStopsVisitor { + public: + id operator()(const mbgl::style::CompositeExponentialStops<MBGLType> &mbglStops) { + NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.stops.size()]; + for (auto const& outerStop: mbglStops.stops) { + stops[@(outerStop.first)] = toConvertedStops(outerStop.second); + } + MGLCompositeStyleFunction *compositeFunction = [MGLCompositeStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential + stops:stops + attributeName:@(mbglFunction.property.c_str()) + options:@{MGLStyleFunctionOptionInterpolationBase: @(mbglStops.base)}]; + if (mbglFunction.defaultValue) { + compositeFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)]; + } + return compositeFunction; + } + + id operator()(const mbgl::style::CompositeIntervalStops<MBGLType> &mbglStops) { + NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.stops.size()]; + for (auto const& outerStop: mbglStops.stops) { + stops[@(outerStop.first)] = toConvertedStops(outerStop.second); + } + 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 mbgl::style::CompositeCategoricalStops<MBGLType> &mbglStops) { + NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.stops.size()]; + for (auto const& outerStop: mbglStops.stops) { + NSMutableDictionary *innerStops = [NSMutableDictionary dictionaryWithCapacity:outerStop.second.size()]; + for (const auto &mbglStop : outerStop.second) { + 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<MBGLType> &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<ObjCType> valueWithRawValue:rawValue]; + } + + id operator()(const mbgl::style::CameraFunction<MBGLType> &mbglValue) const { + CameraFunctionStopsVisitor visitor; + return apply_visitor(visitor, mbglValue.stops); + } + + id operator()(const mbgl::style::SourceFunction<MBGLType> &mbglValue) const { + SourceFunctionStopsVisitor visitor { mbglValue }; + return apply_visitor(visitor, mbglValue.stops); + } + + MGLCompositeStyleFunction<ObjCType> * operator()(const mbgl::style::CompositeFunction<MBGLType> &mbglValue) const { + CompositeFunctionStopsVisitor visitor { mbglValue }; + return apply_visitor(visitor, mbglValue.stops); + } + }; }; |