diff --git a/mapbox-gl-js b/mapbox-gl-js
index b01859294fe..6b96d69ab54 160000
--- a/mapbox-gl-js
+++ b/mapbox-gl-js
@@ -1 +1 @@
-Subproject commit b01859294fec88111601028a539e45be1f088666
+Subproject commit 6b96d69ab54b149db1f6ef06daed37379ac07447
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
index 05c67018a4e..fa4a802e135 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
@@ -81,7 +81,6 @@
* )
* }
*
- *
*/
public class Expression {
@@ -1061,6 +1060,7 @@ public static Expression coalesce(@NonNull Expression... input) {
* );
* }
*
+ *
* @return expression
* @see Style specification
*/
@@ -1081,6 +1081,7 @@ public static Expression properties() {
* );
* }
*
+ *
* @return expression
* @see Style specification
*/
@@ -2294,6 +2295,185 @@ public static Expression max(@Size(min = 1) Number... numbers) {
return max(numberExpression);
}
+ /**
+ * Rounds the input to the nearest integer.
+ * Halfway values are rounded away from zero.
+ * For example `[\"round\", -1.5]` evaluates to -2.
+ *
+ * Example usage:
+ *
+ *
+ * {@code
+ * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id");
+ * circleLayer.setProperties(
+ * circleRadius(round(pi()))
+ * );
+ * }
+ *
+ *
+ * @param expression number expression to round
+ * @return expression
+ * @see Style specification
+ */
+ public static Expression round(Expression expression) {
+ return new Expression("round", expression);
+ }
+
+ /**
+ * Rounds the input to the nearest integer.
+ * Halfway values are rounded away from zero.
+ * For example `[\"round\", -1.5]` evaluates to -2.
+ *
+ * Example usage:
+ *
+ *
+ * {@code
+ * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id");
+ * circleLayer.setProperties(
+ * circleRadius(round(3.14159265359f))
+ * );
+ * }
+ *
+ *
+ * @param number number to round
+ * @return expression
+ * @see Style specification
+ */
+ public static Expression round(Number number) {
+ return round(literal(number));
+ }
+
+ /**
+ * Returns the absolute value of the input.
+ *
+ * Example usage:
+ *
+ *
+ * {@code
+ * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id");
+ * circleLayer.setProperties(
+ * circleRadius(abs(subtract(pi())))
+ * );
+ * }
+ *
+ *
+ * @param expression number expression to get absolute value from
+ * @return expression
+ * @see Style specification
+ */
+ public static Expression abs(Expression expression) {
+ return new Expression("abs", expression);
+ }
+
+ /**
+ * Returns the absolute value of the input.
+ *
+ * Example usage:
+ *
+ *
+ * {@code
+ * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id");
+ * circleLayer.setProperties(
+ * circleRadius(abs(-3.14159265359f))
+ * );
+ * }
+ *
+ *
+ * @param number number to get absolute value from
+ * @return expression
+ * @see Style specification
+ */
+ public static Expression abs(Number number) {
+ return abs(literal(number));
+ }
+
+ /**
+ * Returns the smallest integer that is greater than or equal to the input.
+ *
+ * Example usage:
+ *
+ *
+ * {@code
+ * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id");
+ * circleLayer.setProperties(
+ * circleRadius(ceil(pi()))
+ * );
+ * }
+ *
+ *
+ * @param expression number expression to get value from
+ * @return expression
+ * @see Style specification
+ */
+ public static Expression ceil(Expression expression) {
+ return new Expression("ceil", expression);
+ }
+
+ /**
+ * Returns the smallest integer that is greater than or equal to the input.
+ *
+ * Example usage:
+ *
+ *
+ * {@code
+ * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id");
+ * circleLayer.setProperties(
+ * circleRadius(ceil(3.14159265359))
+ * );
+ * }
+ *
+ * @param number number to get value from
+ * @return expression
+ * @see Style specification
+ */
+ public static Expression ceil(Number number) {
+ return ceil(literal(number));
+ }
+
+ /**
+ * Returns the largest integer that is less than or equal to the input.
+ *
+ * Example usage:
+ *
+ *
+ * {@code
+ * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id");
+ * circleLayer.setProperties(
+ * circleRadius(floor(pi()))
+ * );
+ * }
+ *
+ *
+ * @param expression number expression to get value from
+ * @return expression
+ * @see Style specification
+ */
+ public static Expression floor(Expression expression) {
+ return new Expression("floor", expression);
+ }
+
+ /**
+ * Returns the largest integer that is less than or equal to the input.
+ *
+ * Example usage:
+ *
+ *
+ * {@code
+ * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id");
+ * circleLayer.setProperties(
+ * circleRadius(floor(pi()))
+ * );
+ * }
+ *
+ *
+ * @param number number to get value from
+ * @return expression
+ * @see Style specification
+ */
+ public static Expression floor(Number number) {
+ return floor(literal(number));
+ }
+
/**
* Returns the input string converted to uppercase.
*
@@ -3128,6 +3308,7 @@ public static Interpolator exponential(@NonNull Number base) {
* );
* }
*
+ *
* @param expression base number expression
* @return expression
* @see Style specification
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
index 66d78a40e59..4289deeda3b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
@@ -1856,7 +1856,7 @@ public static PropertyValue iconTextFitPadding(Expression value) {
}
/**
- * Name of image in sprite to use for drawing an image background. Within literal values and zoom functions, property names enclosed in curly brackets (e.g. `{token}`) are replaced with the value of the named property. Expressions and property functions do not support this syntax; for equivalent functionality in expressions, use the [`concat`](#expressions-concat) and [`get`](#expressions-get) operators.
+ * Name of image in sprite to use for drawing an image background.
*
* @param value a String value
* @return property wrapper around String
@@ -1866,7 +1866,7 @@ public static PropertyValue iconImage(String value) {
}
/**
- * Name of image in sprite to use for drawing an image background. Within literal values and zoom functions, property names enclosed in curly brackets (e.g. `{token}`) are replaced with the value of the named property. Expressions and property functions do not support this syntax; for equivalent functionality in expressions, use the [`concat`](#expressions-concat) and [`get`](#expressions-get) operators.
+ * Name of image in sprite to use for drawing an image background.
*
* @param value a String value
* @return property wrapper around String
@@ -2036,7 +2036,7 @@ public static PropertyValue textRotationAlignment(Expression value)
}
/**
- * Value to use for a text label. Within literal values and zoom functions, property names enclosed in curly brackets (e.g. `{token}`) are replaced with the value of the named property. Expressions and property functions do not support this syntax; for equivalent functionality in expressions, use the [`concat`](#expressions-concat) and [`get`](#expressions-get) operators.
+ * Value to use for a text label.
*
* @param value a String value
* @return property wrapper around String
@@ -2046,7 +2046,7 @@ public static PropertyValue textField(String value) {
}
/**
- * Value to use for a text label. Within literal values and zoom functions, property names enclosed in curly brackets (e.g. `{token}`) are replaced with the value of the named property. Expressions and property functions do not support this syntax; for equivalent functionality in expressions, use the [`concat`](#expressions-concat) and [`get`](#expressions-get) operators.
+ * Value to use for a text label.
*
* @param value a String value
* @return property wrapper around String
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java
index 5694242a0a2..45833e8556b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java
@@ -6,6 +6,7 @@
import java.util.Arrays;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.abs;
import static com.mapbox.mapboxsdk.style.expressions.Expression.acos;
import static com.mapbox.mapboxsdk.style.expressions.Expression.all;
import static com.mapbox.mapboxsdk.style.expressions.Expression.any;
@@ -14,6 +15,7 @@
import static com.mapbox.mapboxsdk.style.expressions.Expression.at;
import static com.mapbox.mapboxsdk.style.expressions.Expression.atan;
import static com.mapbox.mapboxsdk.style.expressions.Expression.bool;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.ceil;
import static com.mapbox.mapboxsdk.style.expressions.Expression.coalesce;
import static com.mapbox.mapboxsdk.style.expressions.Expression.color;
import static com.mapbox.mapboxsdk.style.expressions.Expression.concat;
@@ -24,6 +26,7 @@
import static com.mapbox.mapboxsdk.style.expressions.Expression.e;
import static com.mapbox.mapboxsdk.style.expressions.Expression.eq;
import static com.mapbox.mapboxsdk.style.expressions.Expression.exponential;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.floor;
import static com.mapbox.mapboxsdk.style.expressions.Expression.geometryType;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.gt;
@@ -56,6 +59,7 @@
import static com.mapbox.mapboxsdk.style.expressions.Expression.properties;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgba;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.round;
import static com.mapbox.mapboxsdk.style.expressions.Expression.sin;
import static com.mapbox.mapboxsdk.style.expressions.Expression.sqrt;
import static com.mapbox.mapboxsdk.style.expressions.Expression.step;
@@ -1105,4 +1109,60 @@ public void testThrowIllegalArgumentExceptionForPropertyValueLiteral() {
);
expression.toArray();
}
+
+ @Test
+ public void testRound() {
+ Object[] expected = new Object[] {"round", 2.2f};
+ Object[] actual = round(2.2f).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testRoundLiteral() {
+ Object[] expected = new Object[] {"round", 2.2f};
+ Object[] actual = round(literal(2.2f)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testAbs() {
+ Object[] expected = new Object[] {"abs", -2.2f};
+ Object[] actual = abs(-2.2f).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testAbsLiteral() {
+ Object[] expected = new Object[] {"abs", -2.2f};
+ Object[] actual = abs(literal(-2.2f)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testCeil() {
+ Object[] expected = new Object[] {"ceil", 2.2f};
+ Object[] actual = ceil(2.2f).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testCeilLiteral() {
+ Object[] expected = new Object[] {"ceil", 2.2f};
+ Object[] actual = ceil(literal(2.2f)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testFloor() {
+ Object[] expected = new Object[] {"floor", 2.2f};
+ Object[] actual = floor(2.2f).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testFloorLiteral() {
+ Object[] expected = new Object[] {"floor", 2.2f};
+ Object[] actual = floor(literal(2.2f)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
}
\ No newline at end of file
diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs
index d61b2921487..857d03d6e7c 100644
--- a/platform/darwin/docs/guides/For Style Authors.md.ejs
+++ b/platform/darwin/docs/guides/For Style Authors.md.ejs
@@ -379,11 +379,14 @@ In style specification | Method, function, or predicate type | Format string syn
`%` | `modulus:by:` |
`^` | `raise:toPower:` | `2 ** 2`
`+` | `add:to:` | `1 + 2`
+`abs` | `abs:` | `abs(-1)`
`acos` | |
`asin` | |
`atan` | |
+`ceil` | `ceiling:` | `ceiling(0.99999)`
`cos` | |
`e` | | `%@` representing `NSNumber` containing `M_E`
+`floor` | `floor:` | `floor(-0.99999)`
`ln` | `ln:` | `ln(2)`
`ln2` | | `%@` representing `NSNumber` containing `M_LN2`
`log10` | `log:` | `log(1)`
@@ -391,6 +394,7 @@ In style specification | Method, function, or predicate type | Format string syn
`max` | `max:` | `max({1, 2, 2, 3, 4, 7, 9})`
`min` | `min:` | `min({1, 2, 2, 3, 4, 7, 9})`
`pi` | | `%@` representing `NSNumber` containing `M_PI`
+`round` | `mgl_round:` | `mgl_round(1.5)`
`sin` | |
`sqrt` | `sqrt:` | `sqrt(2)`
`tan` | |
diff --git a/platform/darwin/docs/guides/Predicates and Expressions.md b/platform/darwin/docs/guides/Predicates and Expressions.md
index 13204b09a6b..1b8714811db 100644
--- a/platform/darwin/docs/guides/Predicates and Expressions.md
+++ b/platform/darwin/docs/guides/Predicates and Expressions.md
@@ -196,6 +196,7 @@ Initializer parameter | Format string syntax | Description
`mgl_interpolate:withCurveType:parameters:stops:` | `mgl_interpolate:withCurveType:parameters:stops:(x, 'linear', nil, %@)` | Produces continuous, smooth results by interpolating between pairs of input and output values (“stops”). Compared to the `mgl_interpolateWithCurveType:parameters:stops:` custom function, the input expression (that function’s target) is instead passed in as the first argument to this function.
`mgl_step:from:stops:` | `mgl_step:from:stops:(x, 11, %@)` | Produces discrete, stepped results by evaluating a piecewise-constant function defined by pairs of input and output values ("stops"). Compared to the `mgl_stepWithMinimum:stops:` custom function, the input expression (that function’s target) is instead passed in as the first argument to this function.
`mgl_join:` | `mgl_join({'Old', 'MacDonald'})` | Returns the result of concatenating together all the elements of an array in order. Compared to the `stringByAppendingString:` custom function, this function takes only one argument, which is an aggregate expression containing the strings to concatenate.
+`mgl_round:` | `mgl_round(1.5)` | Returns the number rounded to the nearest integer. If the number is halfway between two integers, this function rounds it away from zero.
`mgl_coalesce:` | `mgl_coalesce({x, y, z})` | Returns the first non-`nil` value from an array of expressions.
`MGL_LET` | `MGL_LET('age', uppercase('old'), 'name', uppercase('MacDonald'), mgl_join({$age, $name}))` | Any number of variable names interspersed with their assigned `NSExpression` values, followed by an `NSExpression` that may contain references to those variables. Compared to the `mgl_expressionWithContext:` custom function, this function takes the variable names and values inline before the expression that contains references to those variables.
`MGL_MATCH` | `MGL_MATCH(x, 0, 'zero match', 1, 'one match', 'two match', 'default')` | Evaluates the first expression and returns the value that matches the initial condition. After the first expression condition a pair of matching/return value should be added and a default value.
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm
index 8c82c84c7d6..6a61dd9abb4 100644
--- a/platform/darwin/src/NSExpression+MGLAdditions.mm
+++ b/platform/darwin/src/NSExpression+MGLAdditions.mm
@@ -58,6 +58,7 @@ + (void)installFunctions {
// Install method-like functions, taking the number of arguments implied by
// the selector name.
INSTALL_METHOD(mgl_join:);
+ INSTALL_METHOD(mgl_round:);
INSTALL_METHOD(mgl_interpolate:withCurveType:parameters:stops:);
INSTALL_METHOD(mgl_step:from:stops:);
INSTALL_METHOD(mgl_coalesce:);
@@ -83,6 +84,14 @@ - (NSString *)mgl_join:(NSArray *)components {
return [components componentsJoinedByString:@""];
}
+/**
+ Rounds the given number to the nearest integer. If the number is halfway
+ between two integers, this method rounds it away from zero.
+ */
+- (NSNumber *)mgl_round:(NSNumber *)number {
+ return @(round(number.doubleValue));
+}
+
/**
A placeholder for a method that evaluates an interpolation expression.
*/
@@ -487,6 +496,10 @@ + (instancetype)mgl_expressionWithJSONObject:(id)object {
@"sqrt": @"sqrt:",
@"log10": @"log:",
@"ln": @"ln:",
+ @"abs": @"abs:",
+ @"round": @"mgl_round:",
+ @"floor": @"floor:",
+ @"ceil": @"ceiling:",
@"^": @"raise:toPower:",
@"upcase": @"uppercase:",
@"downcase": @"lowercase:",
@@ -720,9 +733,13 @@ - (id)mgl_jsonExpressionObject {
@"log:": @"log10",
@"ln:": @"ln",
@"raise:toPower:": @"^",
+ @"ceiling:": @"ceil",
+ @"abs:": @"abs",
+ @"floor:": @"floor",
@"uppercase:": @"upcase",
@"lowercase:": @"downcase",
@"length:": @"length",
+ @"mgl_round:": @"round",
// Vararg aftermarket expressions need to be declared with an explicit and implicit first argument.
@"MGL_LET": @"let",
@"MGL_LET:": @"let",
@@ -826,18 +843,9 @@ - (id)mgl_jsonExpressionObject {
return [@[@"max"] arrayByAddingObjectsFromArray:arguments];
} else if ([function isEqualToString:@"exp:"]) {
return [NSExpression expressionForFunction:@"raise:toPower:" arguments:@[@(M_E), self.arguments.firstObject]].mgl_jsonExpressionObject;
- } else if ([function isEqualToString:@"ceiling:"]) {
- return [NSExpression expressionWithFormat:@"trunc:(%@) + TERNARY(modulus:by:(%@, 1) > 0, 1, 0)",
- self.arguments.firstObject, self.arguments.firstObject].mgl_jsonExpressionObject;
} else if ([function isEqualToString:@"trunc:"]) {
return [NSExpression expressionWithFormat:@"%@ - modulus:by:(%@, 1)",
self.arguments.firstObject, self.arguments.firstObject].mgl_jsonExpressionObject;
- } else if ([function isEqualToString:@"abs:"]) {
- return [NSExpression expressionWithFormat:@"%@ * TERNARY(%@ > 0, 1, -1)",
- self.arguments.firstObject, self.arguments.firstObject].mgl_jsonExpressionObject;
- } else if ([function isEqualToString:@"floor:"]) {
- return [NSExpression expressionWithFormat:@"trunc:(%@) - TERNARY(modulus:by:(%@, 1) < 0, 1, 0)",
- self.arguments.firstObject, self.arguments.firstObject].mgl_jsonExpressionObject;
} else if ([function isEqualToString:@"mgl_join:"]) {
NSArray *arguments = [self.arguments.firstObject.collection valueForKeyPath:@"mgl_jsonExpressionObject"];
return [@[@"concat"] arrayByAddingObjectsFromArray:arguments];
diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm
index 579d2505f2b..236c8d1ad9b 100644
--- a/platform/darwin/test/MGLExpressionTests.mm
+++ b/platform/darwin/test/MGLExpressionTests.mm
@@ -393,29 +393,25 @@ - (void)testArithmeticExpressionObject {
}
{
NSExpression *expression = [NSExpression expressionForFunction:@"ceiling:" arguments:@[MGLConstantExpression(@1.5)]];
- NSArray *jsonTruncation = @[@"-", @1.5, @[@"%", @1.5, @1]];
- NSArray *jsonExpression = @[@"+", jsonTruncation, @[@"case", @[@">", @[@"%", @1.5, @1], @0], @1, @0]];
+ NSArray *jsonExpression = @[@"ceil", @1.5];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @2);
}
{
NSExpression *expression = [NSExpression expressionForFunction:@"ceiling:" arguments:@[MGLConstantExpression(@-1.5)]];
- NSArray *jsonTruncation = @[@"-", @-1.5, @[@"%", @-1.5, @1]];
- NSArray *jsonExpression = @[@"+", jsonTruncation, @[@"case", @[@">", @[@"%", @-1.5, @1], @0], @1, @0]];
+ NSArray *jsonExpression = @[@"ceil", @-1.5];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @-1);
}
{
NSExpression *expression = [NSExpression expressionForFunction:@"ceiling:" arguments:@[MGLConstantExpression(@2)]];
- NSArray *jsonTruncation = @[@"-", @2, @[@"%", @2, @1]];
- NSArray *jsonExpression = @[@"+", jsonTruncation, @[@"case", @[@">", @[@"%", @2, @1], @0], @1, @0]];
+ NSArray *jsonExpression = @[@"ceil", @2];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @2);
}
{
NSExpression *expression = [NSExpression expressionForFunction:@"ceiling:" arguments:@[MGLConstantExpression(@-2)]];
- NSArray *jsonTruncation = @[@"-", @-2, @[@"%", @-2, @1]];
- NSArray *jsonExpression = @[@"+", jsonTruncation, @[@"case", @[@">", @[@"%", @-2, @1], @0], @1, @0]];
+ NSArray *jsonExpression = @[@"ceil", @-2];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @-2);
}
@@ -433,44 +429,64 @@ - (void)testArithmeticExpressionObject {
}
{
NSExpression *expression = [NSExpression expressionForFunction:@"abs:" arguments:@[MGLConstantExpression(@2)]];
- NSArray *jsonExpression = @[@"*", @2, @[@"case", @[@">", @2, @0], @1, @-1]];
+ NSArray *jsonExpression = @[@"abs", @2];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @2);
}
{
NSExpression *expression = [NSExpression expressionForFunction:@"abs:" arguments:@[MGLConstantExpression(@-2)]];
- NSArray *jsonExpression = @[@"*", @-2, @[@"case", @[@">", @-2, @0], @1, @-1]];
+ NSArray *jsonExpression = @[@"abs", @-2];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @2);
}
{
NSExpression *expression = [NSExpression expressionForFunction:@"floor:" arguments:@[MGLConstantExpression(@1.5)]];
- NSArray *jsonTruncation = @[@"-", @1.5, @[@"%", @1.5, @1]];
- NSArray *jsonExpression = @[@"-", jsonTruncation, @[@"case", @[@"<", @[@"%", @1.5, @1], @0], @1, @0]];
+ NSArray *jsonExpression = @[@"floor", @1.5];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @1);
}
{
NSExpression *expression = [NSExpression expressionForFunction:@"floor:" arguments:@[MGLConstantExpression(@-1.5)]];
- NSArray *jsonTruncation = @[@"-", @-1.5, @[@"%", @-1.5, @1]];
- NSArray *jsonExpression = @[@"-", jsonTruncation, @[@"case", @[@"<", @[@"%", @-1.5, @1], @0], @1, @0]];
+ NSArray *jsonExpression = @[@"floor", @-1.5];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @-2);
}
{
NSExpression *expression = [NSExpression expressionForFunction:@"floor:" arguments:@[MGLConstantExpression(@2)]];
- NSArray *jsonTruncation = @[@"-", @2, @[@"%", @2, @1]];
- NSArray *jsonExpression = @[@"-", jsonTruncation, @[@"case", @[@"<", @[@"%", @2, @1], @0], @1, @0]];
+ NSArray *jsonExpression = @[@"floor", @2];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @2);
}
{
NSExpression *expression = [NSExpression expressionForFunction:@"floor:" arguments:@[MGLConstantExpression(@-2)]];
- NSArray *jsonTruncation = @[@"-", @-2, @[@"%", @-2, @1]];
- NSArray *jsonExpression = @[@"-", jsonTruncation, @[@"case", @[@"<", @[@"%", @-2, @1], @0], @1, @0]];
+ NSArray *jsonExpression = @[@"floor", @-2];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @-2);
}
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_round:" arguments:@[MGLConstantExpression(@1.5)]];
+ NSArray *jsonExpression = @[@"round", @1.5];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @2);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_round:" arguments:@[MGLConstantExpression(@-1.5)]];
+ NSArray *jsonExpression = @[@"round", @-1.5];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @-2);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_round:" arguments:@[MGLConstantExpression(@2.5)]];
+ NSArray *jsonExpression = @[@"round", @2.5];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @3);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForFunction:@"mgl_round:" arguments:@[MGLConstantExpression(@-2.5)]];
+ NSArray *jsonExpression = @[@"round", @-2.5];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @-3);
+ }
}
- (void)testTrigonometricExpressionObject {
diff --git a/platform/ios/docs/guides/For Style Authors.md b/platform/ios/docs/guides/For Style Authors.md
index 6b8839ecbe8..87da59162e5 100644
--- a/platform/ios/docs/guides/For Style Authors.md
+++ b/platform/ios/docs/guides/For Style Authors.md
@@ -364,11 +364,14 @@ In style specification | Method, function, or predicate type | Format string syn
`%` | `modulus:by:` |
`^` | `raise:toPower:` | `2 ** 2`
`+` | `add:to:` | `1 + 2`
+`abs` | `abs:` | `abs(-1)`
`acos` | |
`asin` | |
`atan` | |
+`ceil` | `ceiling:` | `ceiling(0.99999)`
`cos` | |
`e` | | `%@` representing `NSNumber` containing `M_E`
+`floor` | `floor:` | `floor(-0.99999)`
`ln` | `ln:` | `ln(2)`
`ln2` | | `%@` representing `NSNumber` containing `M_LN2`
`log10` | `log:` | `log(1)`
@@ -376,6 +379,7 @@ In style specification | Method, function, or predicate type | Format string syn
`max` | `max:` | `max({1, 2, 2, 3, 4, 7, 9})`
`min` | `min:` | `min({1, 2, 2, 3, 4, 7, 9})`
`pi` | | `%@` representing `NSNumber` containing `M_PI`
+`round` | `mgl_round:` | `mgl_round(1.5)`
`sin` | |
`sqrt` | `sqrt:` | `sqrt(2)`
`tan` | |
diff --git a/platform/macos/docs/guides/For Style Authors.md b/platform/macos/docs/guides/For Style Authors.md
index 8bd2e04d2b5..e90858c6649 100644
--- a/platform/macos/docs/guides/For Style Authors.md
+++ b/platform/macos/docs/guides/For Style Authors.md
@@ -357,11 +357,14 @@ In style specification | Method, function, or predicate type | Format string syn
`%` | `modulus:by:` |
`^` | `raise:toPower:` | `2 ** 2`
`+` | `add:to:` | `1 + 2`
+`abs` | `abs:` | `abs(-1)`
`acos` | |
`asin` | |
`atan` | |
+`ceil` | `ceiling:` | `ceiling(0.99999)`
`cos` | |
`e` | | `%@` representing `NSNumber` containing `M_E`
+`floor` | `floor:` | `floor(-0.99999)`
`ln` | `ln:` | `ln(2)`
`ln2` | | `%@` representing `NSNumber` containing `M_LN2`
`log10` | `log:` | `log(1)`
@@ -369,6 +372,7 @@ In style specification | Method, function, or predicate type | Format string syn
`max` | `max:` | `max({1, 2, 2, 3, 4, 7, 9})`
`min` | `min:` | `min({1, 2, 2, 3, 4, 7, 9})`
`pi` | | `%@` representing `NSNumber` containing `M_PI`
+`round` | `mgl_round:` | `mgl_round(1.5)`
`sin` | |
`sqrt` | `sqrt:` | `sqrt(2)`
`tan` | |
diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp
index 77b294b3807..c36ffa33e35 100644
--- a/src/mbgl/style/expression/compound_expression.cpp
+++ b/src/mbgl/style/expression/compound_expression.cpp
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
namespace mbgl {
namespace style {
@@ -362,6 +363,11 @@ std::unordered_map initiali
return result;
});
+ define("round", [](double x) -> Result { return std::round(x); });
+ define("floor", [](double x) -> Result { return std::floor(x); });
+ define("ceil", [](double x) -> Result { return std::ceil(x); });
+ define("abs", [](double x) -> Result { return std::abs(x); });
+
define(">", [](double lhs, double rhs) -> Result { return lhs > rhs; });
define(">", [](const std::string& lhs, const std::string& rhs) -> Result { return lhs > rhs; });
define(">=", [](double lhs, double rhs) -> Result { return lhs >= rhs; });