Files
MapLibreParticleLab/platform/darwin/src/NSExpression+MGLAdditions.mm
Minh Nguyễn 8669f933fd [ios, macos] Convert NSColor/UIColor expressions to CSS color string values
When converting a constant NSExpression to an mbgl::Value, turn an NSColor or UIColor into an std::string containing a CSS color string. This allows developers to set an attribute of an MGLFeature to an NSColor or UIColor (rather than a CSS color string, which would be foreign), then use it in an MGLStyleFunction with identity interpolation.
2017-02-18 14:42:16 -08:00

157 lines
6.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#import "NSExpression+MGLAdditions.h"
#import "MGLTypes.h"
#if TARGET_OS_IPHONE
#import "UIColor+MGLAdditions.h"
#else
#import "NSColor+MGLAdditions.h"
#endif
@implementation NSExpression (MGLAdditions)
- (std::vector<mbgl::Value>)mgl_aggregateMBGLValue {
if ([self.constantValue isKindOfClass:[NSArray class]] || [self.constantValue isKindOfClass:[NSSet class]]) {
std::vector<mbgl::Value> convertedValues;
for (id value in self.constantValue) {
NSExpression *expression = value;
if (![expression isKindOfClass:[NSExpression class]]) {
expression = [NSExpression expressionForConstantValue:expression];
}
convertedValues.push_back(expression.mgl_constantMBGLValue);
}
return convertedValues;
}
[NSException raise:NSInvalidArgumentException
format:@"Constant value expression must contain an array or set."];
return {};
}
- (mbgl::Value)mgl_constantMBGLValue {
id value = self.constantValue;
if ([value isKindOfClass:NSString.class]) {
return { std::string([(NSString *)value UTF8String]) };
} else if ([value isKindOfClass:NSNumber.class]) {
NSNumber *number = (NSNumber *)value;
if ((strcmp([number objCType], @encode(char)) == 0) ||
(strcmp([number objCType], @encode(BOOL)) == 0)) {
// char: 32-bit boolean
// BOOL: 64-bit boolean
return { (bool)number.boolValue };
} else if (strcmp([number objCType], @encode(double)) == 0) {
// Double values on all platforms are interpreted precisely.
return { (double)number.doubleValue };
} else if (strcmp([number objCType], @encode(float)) == 0) {
// Float values when taken as double introduce precision problems,
// so warn the user to avoid them. This would require them to
// explicitly use -[NSNumber numberWithFloat:] arguments anyway.
// We still do this conversion in order to provide a valid value.
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"Float value in expression will be converted to a double; some imprecision may result. "
@"Use double values explicitly when specifying constant expression values and "
@"when specifying arguments to predicate and expression format strings. "
@"This will be logged only once.");
});
return { (double)number.doubleValue };
} else if ([number compare:@(0)] == NSOrderedDescending ||
[number compare:@(0)] == NSOrderedSame) {
// Positive integer or zero; use uint64_t per mbgl::Value definition.
// We use unsigned long long here to avoid any truncation.
return { (uint64_t)number.unsignedLongLongValue };
} else if ([number compare:@(0)] == NSOrderedAscending) {
// Negative integer; use int64_t per mbgl::Value definition.
// We use long long here to avoid any truncation.
return { (int64_t)number.longLongValue };
}
} else if ([value isKindOfClass:[MGLColor class]]) {
auto hexString = [(MGLColor *)value mgl_color].stringify();
return { hexString };
} else if (value && value != [NSNull null]) {
[NSException raise:NSInvalidArgumentException
format:@"Can’t convert %s:%@ to mbgl::Value", [value objCType], value];
}
return {};
}
- (std::vector<mbgl::FeatureType>)mgl_aggregateFeatureType {
if ([self.constantValue isKindOfClass:[NSArray class]] || [self.constantValue isKindOfClass:[NSSet class]]) {
std::vector<mbgl::FeatureType> convertedValues;
for (id value in self.constantValue) {
NSExpression *expression = value;
if (![expression isKindOfClass:[NSExpression class]]) {
expression = [NSExpression expressionForConstantValue:expression];
}
convertedValues.push_back(expression.mgl_featureType);
}
return convertedValues;
}
[NSException raise:NSInvalidArgumentException
format:@"Constant value expression must contain an array or set."];
return {};
}
- (mbgl::FeatureType)mgl_featureType {
id value = self.constantValue;
if ([value isKindOfClass:NSString.class]) {
if ([value isEqualToString:@"Point"]) {
return mbgl::FeatureType::Point;
}
if ([value isEqualToString:@"LineString"]) {
return mbgl::FeatureType::LineString;
}
if ([value isEqualToString:@"Polygon"]) {
return mbgl::FeatureType::Polygon;
}
} else if ([value isKindOfClass:NSNumber.class]) {
switch ([value integerValue]) {
case 1:
return mbgl::FeatureType::Point;
case 2:
return mbgl::FeatureType::LineString;
case 3:
return mbgl::FeatureType::Polygon;
default:
break;
}
}
return mbgl::FeatureType::Unknown;
}
- (std::vector<mbgl::FeatureIdentifier>)mgl_aggregateFeatureIdentifier {
if ([self.constantValue isKindOfClass:[NSArray class]] || [self.constantValue isKindOfClass:[NSSet class]]) {
std::vector<mbgl::FeatureIdentifier> convertedValues;
for (id value in self.constantValue) {
NSExpression *expression = value;
if (![expression isKindOfClass:[NSExpression class]]) {
expression = [NSExpression expressionForConstantValue:expression];
}
convertedValues.push_back(expression.mgl_featureIdentifier);
}
return convertedValues;
}
[NSException raise:NSInvalidArgumentException
format:@"Constant value expression must contain an array or set."];
return {};
}
- (mbgl::FeatureIdentifier)mgl_featureIdentifier {
mbgl::Value mbglValue = self.mgl_constantMBGLValue;
if (mbglValue.is<std::string>()) {
return mbglValue.get<std::string>();
}
if (mbglValue.is<double>()) {
return mbglValue.get<double>();
}
if (mbglValue.is<uint64_t>()) {
return mbglValue.get<uint64_t>();
}
if (mbglValue.is<int64_t>()) {
return mbglValue.get<int64_t>();
}
return {};
}
@end