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

Eviscerate mbgl expression to Foundation JSON object conversion #11389

Merged
merged 13 commits into from
Mar 30, 2018
Merged
87 changes: 6 additions & 81 deletions platform/darwin/src/MGLStyleValue.mm
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
const MGLStyleFunctionOption MGLStyleFunctionOptionInterpolationBase = @"MGLStyleFunctionOptionInterpolationBase";
const MGLStyleFunctionOption MGLStyleFunctionOptionDefaultValue = @"MGLStyleFunctionOptionDefaultValue";

id MGLJSONObjectFromMBGLValue(const mbgl::style::expression::Value &value) {
id MGLJSONObjectFromMBGLValue(const mbgl::Value &value) {
return value.match([](const mbgl::NullValue) -> id {
return [NSNull null];
}, [](const bool value) {
Expand All @@ -24,98 +24,23 @@ id MGLJSONObjectFromMBGLValue(const mbgl::style::expression::Value &value) {
std::array<float, 3> spherical = value.getSpherical();
MGLSphericalPosition position = MGLSphericalPositionMake(spherical[0], spherical[1], spherical[2]);
return [NSValue valueWithMGLSphericalPosition:position];
}, [&](const std::vector<mbgl::style::expression::Value> &vector) {
}, [&](const std::vector<mbgl::Value> &vector) {
NSMutableArray *array = [NSMutableArray arrayWithCapacity:vector.size()];
for (auto value : vector) {
[array addObject:MGLJSONObjectFromMBGLValue(value)];
}
return @[@"literal", array];
}, [&](const std::unordered_map<std::string, mbgl::style::expression::Value> &map) {
return array;
}, [&](const std::unordered_map<std::string, mbgl::Value> &map) {
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:map.size()];
for (auto &item : map) {
dictionary[@(item.first.c_str())] = MGLJSONObjectFromMBGLValue(item.second);
}
return @[@"literal", dictionary];
return dictionary;
}, [](const auto &) -> id {
return nil;
});
}

id MGLJSONObjectFromMBGLExpression(const mbgl::style::expression::Expression &mbglExpression) {
using namespace mbgl::style::expression;
if (auto literalExpression = dynamic_cast<const Literal *>(&mbglExpression)) {
auto result = literalExpression->evaluate({ nullptr });
return result ? MGLJSONObjectFromMBGLValue(*result) : nil;
}
if (auto assertExpression = dynamic_cast<const ArrayAssertion *>(&mbglExpression)) {
NSMutableArray *inputs = [NSMutableArray array];
assertExpression->eachChild([&](const Expression &child) {
[inputs addObject:MGLJSONObjectFromMBGLExpression(child)];
});
return @[@"literal", inputs.lastObject];
}
if (auto assertExpression = dynamic_cast<const Assertion *>(&mbglExpression)) {
NSMutableArray *inputs = [NSMutableArray array];
assertExpression->eachChild([&](const Expression &child) {
[inputs addObject:MGLJSONObjectFromMBGLExpression(child)];
});
return inputs.firstObject;
}
if (auto compoundExpression = dynamic_cast<const CompoundExpressionBase *>(&mbglExpression)) {
const std::string name = compoundExpression->getName();
mbgl::optional<std::size_t> parameterCount = compoundExpression->getParameterCount();
NSMutableArray *expressionObject = parameterCount ? [NSMutableArray arrayWithCapacity:*parameterCount + 1] : [NSMutableArray array];
[expressionObject addObject:@(name.c_str())];
compoundExpression->eachChild([&](const Expression &child) {
[expressionObject addObject:MGLJSONObjectFromMBGLExpression(child)];
});
return expressionObject;
}
if (auto stepExpression = dynamic_cast<const Step *>(&mbglExpression)) {
auto &input = stepExpression->getInput();
NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"step", MGLJSONObjectFromMBGLExpression(*input.get()), nil];
stepExpression->eachStop([&](double stop, const Expression &child) {
[expressionObject addObject:@(stop)];
[expressionObject addObject:MGLJSONObjectFromMBGLExpression(child)];
});
if ([expressionObject[2] isEqual:@(-INFINITY)]) {
[expressionObject removeObjectAtIndex:2];
}
return expressionObject;
}
if (auto interpolateExpression = dynamic_cast<const InterpolateBase *>(&mbglExpression)) {
auto &interpolator = interpolateExpression->getInterpolator();
auto &input = interpolateExpression->getInput();
NSArray *interpolatorObject;
if (interpolator.is<ExponentialInterpolator>()) {
auto exponentialInterpolator = interpolator.get<ExponentialInterpolator>();
interpolatorObject = exponentialInterpolator.base == 1 ? @[@"linear"] : @[@"exponential", @(exponentialInterpolator.base)];
} else if (interpolator.is<CubicBezierInterpolator>()) {
auto cubicBezierInterpolator = interpolator.get<CubicBezierInterpolator>();
auto bezier = cubicBezierInterpolator.ub;
interpolatorObject = @[
@"cubic-bezier",
@(bezier.getP1().first), @(bezier.getP1().second),
@(bezier.getP2().first), @(bezier.getP2().second),
];
} else {
NSCAssert(NO, @"Unrecognized interpolator type.");
}
NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"interpolate", interpolatorObject, MGLJSONObjectFromMBGLExpression(*input.get()), nil];
interpolateExpression->eachStop([&](double stop, const Expression &child) {
[expressionObject addObject:@(stop)];
[expressionObject addObject:MGLJSONObjectFromMBGLExpression(child)];
});
return expressionObject;
}
if (auto caseExpression = dynamic_cast<const Case *>(&mbglExpression)) {
NSMutableArray *expressionObject = [NSMutableArray arrayWithObject:@"case"];
caseExpression->eachChild([&](const Expression &child) {
[expressionObject addObject:MGLJSONObjectFromMBGLExpression(child)];
});
return expressionObject;
}
NSCAssert(NO, @"Unrecognized expression type.");
return nil;
return MGLJSONObjectFromMBGLValue(mbglExpression.serialize());
}

14 changes: 12 additions & 2 deletions platform/darwin/src/NSExpression+MGLAdditions.mm
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ + (instancetype)mgl_expressionWithJSONObject:(id)object {
} else if ([op isEqualToString:@"to-boolean"]) {
NSExpression *operand = [NSExpression mgl_expressionWithJSONObject:argumentObjects.firstObject];
return [NSExpression expressionForFunction:operand selectorName:@"boolValue" arguments:@[]];
} else if ([op isEqualToString:@"to-number"]) {
} else if ([op isEqualToString:@"to-number"] || [op isEqualToString:@"number"]) {
NSExpression *operand = [NSExpression mgl_expressionWithJSONObject:argumentObjects.firstObject];
if (argumentObjects.count == 1) {
return [NSExpression expressionWithFormat:@"CAST(%@, 'NSNumber')", operand];
Expand Down Expand Up @@ -570,6 +570,12 @@ + (instancetype)mgl_expressionWithJSONObject:(id)object {
function = @"length:";
}
return [NSExpression expressionForFunction:function arguments:@[subexpressions.firstObject]];
} else if ([op isEqualToString:@"rgb"]) {
NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(argumentObjects);
return [NSExpression mgl_expressionForRGBComponents:subexpressions];
} else if ([op isEqualToString:@"rgba"]) {
NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(argumentObjects);
return [NSExpression mgl_expressionForRGBAComponents:subexpressions];
} else if ([op isEqualToString:@"min"]) {
NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(argumentObjects);
NSExpression *subexpression = [NSExpression expressionForAggregate:subexpressions];
Expand Down Expand Up @@ -842,7 +848,8 @@ - (id)mgl_jsonExpressionObject {
return @[@"at", self.arguments[1].mgl_jsonExpressionObject, self.arguments[0].mgl_jsonExpressionObject];
} else if ([function isEqualToString:@"boolValue"]) {
return @[@"to-boolean", self.operand.mgl_jsonExpressionObject];
} else if ([function isEqualToString:@"mgl_numberWithFallbackValues:"] ||
} else if ([function isEqualToString:@"mgl_number"] ||
[function isEqualToString:@"mgl_numberWithFallbackValues:"] ||
[function isEqualToString:@"decimalValue"] ||
[function isEqualToString:@"floatValue"] ||
[function isEqualToString:@"doubleValue"]) {
Expand Down Expand Up @@ -895,6 +902,9 @@ - (id)mgl_jsonExpressionObject {
format:@"Casting expression to %@ not yet implemented.", type];
} else if ([function isEqualToString:@"MGL_FUNCTION"]) {
return self.arguments.mgl_jsonExpressionObject;
} else if (op == [MGLColor class] && [function isEqualToString:@"colorWithRed:green:blue:alpha:"]) {
NSArray *arguments = self.arguments.mgl_jsonExpressionObject;
return [@[@"rgba"] arrayByAddingObjectsFromArray:arguments];
} else if ([function isEqualToString:@"median:"] ||
[function isEqualToString:@"mode:"] ||
[function isEqualToString:@"stddev:"] ||
Expand Down
42 changes: 28 additions & 14 deletions platform/darwin/test/MGLCircleStyleLayerTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ - (void)testProperties {

XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue,
@"Setting circleBlur to a data expression should update circle-blur.");
XCTAssertEqualObjects(layer.circleBlur, functionExpression,
NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
XCTAssertEqualObjects(layer.circleBlur, pedanticFunctionExpression,
@"circleBlur should round-trip data expressions.");

functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
Expand All @@ -98,7 +99,8 @@ - (void)testProperties {

XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue,
@"Setting circleBlur to a camera-data expression should update circle-blur.");
XCTAssertEqualObjects(layer.circleBlur, functionExpression,
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleBlur, pedanticFunctionExpression,
@"circleBlur should round-trip camera-data expressions.");


Expand Down Expand Up @@ -155,7 +157,8 @@ - (void)testProperties {

XCTAssertEqual(rawLayer->getCircleColor(), propertyValue,
@"Setting circleColor to a data expression should update circle-color.");
XCTAssertEqualObjects(layer.circleColor, functionExpression,
NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
XCTAssertEqualObjects(layer.circleColor, pedanticFunctionExpression,
@"circleColor should round-trip data expressions.");

functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
Expand All @@ -168,7 +171,8 @@ - (void)testProperties {

XCTAssertEqual(rawLayer->getCircleColor(), propertyValue,
@"Setting circleColor to a camera-data expression should update circle-color.");
XCTAssertEqualObjects(layer.circleColor, functionExpression,
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleColor, pedanticFunctionExpression,
@"circleColor should round-trip camera-data expressions.");


Expand Down Expand Up @@ -225,7 +229,8 @@ - (void)testProperties {

XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue,
@"Setting circleOpacity to a data expression should update circle-opacity.");
XCTAssertEqualObjects(layer.circleOpacity, functionExpression,
NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
XCTAssertEqualObjects(layer.circleOpacity, pedanticFunctionExpression,
@"circleOpacity should round-trip data expressions.");

functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
Expand All @@ -238,7 +243,8 @@ - (void)testProperties {

XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue,
@"Setting circleOpacity to a camera-data expression should update circle-opacity.");
XCTAssertEqualObjects(layer.circleOpacity, functionExpression,
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleOpacity, pedanticFunctionExpression,
@"circleOpacity should round-trip camera-data expressions.");


Expand Down Expand Up @@ -339,7 +345,8 @@ - (void)testProperties {

XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue,
@"Setting circleRadius to a data expression should update circle-radius.");
XCTAssertEqualObjects(layer.circleRadius, functionExpression,
NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
XCTAssertEqualObjects(layer.circleRadius, pedanticFunctionExpression,
@"circleRadius should round-trip data expressions.");

functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
Expand All @@ -352,7 +359,8 @@ - (void)testProperties {

XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue,
@"Setting circleRadius to a camera-data expression should update circle-radius.");
XCTAssertEqualObjects(layer.circleRadius, functionExpression,
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleRadius, pedanticFunctionExpression,
@"circleRadius should round-trip camera-data expressions.");


Expand Down Expand Up @@ -453,7 +461,8 @@ - (void)testProperties {

XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue,
@"Setting circleStrokeColor to a data expression should update circle-stroke-color.");
XCTAssertEqualObjects(layer.circleStrokeColor, functionExpression,
NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
XCTAssertEqualObjects(layer.circleStrokeColor, pedanticFunctionExpression,
@"circleStrokeColor should round-trip data expressions.");

functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
Expand All @@ -466,7 +475,8 @@ - (void)testProperties {

XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue,
@"Setting circleStrokeColor to a camera-data expression should update circle-stroke-color.");
XCTAssertEqualObjects(layer.circleStrokeColor, functionExpression,
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleStrokeColor, pedanticFunctionExpression,
@"circleStrokeColor should round-trip camera-data expressions.");


Expand Down Expand Up @@ -523,7 +533,8 @@ - (void)testProperties {

XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue,
@"Setting circleStrokeOpacity to a data expression should update circle-stroke-opacity.");
XCTAssertEqualObjects(layer.circleStrokeOpacity, functionExpression,
NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
XCTAssertEqualObjects(layer.circleStrokeOpacity, pedanticFunctionExpression,
@"circleStrokeOpacity should round-trip data expressions.");

functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
Expand All @@ -536,7 +547,8 @@ - (void)testProperties {

XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue,
@"Setting circleStrokeOpacity to a camera-data expression should update circle-stroke-opacity.");
XCTAssertEqualObjects(layer.circleStrokeOpacity, functionExpression,
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleStrokeOpacity, pedanticFunctionExpression,
@"circleStrokeOpacity should round-trip camera-data expressions.");


Expand Down Expand Up @@ -593,7 +605,8 @@ - (void)testProperties {

XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue,
@"Setting circleStrokeWidth to a data expression should update circle-stroke-width.");
XCTAssertEqualObjects(layer.circleStrokeWidth, functionExpression,
NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
XCTAssertEqualObjects(layer.circleStrokeWidth, pedanticFunctionExpression,
@"circleStrokeWidth should round-trip data expressions.");

functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
Expand All @@ -606,7 +619,8 @@ - (void)testProperties {

XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue,
@"Setting circleStrokeWidth to a camera-data expression should update circle-stroke-width.");
XCTAssertEqualObjects(layer.circleStrokeWidth, functionExpression,
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleStrokeWidth, pedanticFunctionExpression,
@"circleStrokeWidth should round-trip camera-data expressions.");


Expand Down
Loading