diff options
author | Anand Thakker <anandthakker@users.noreply.github.com> | 2018-04-11 12:03:56 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-11 12:03:56 -0400 |
commit | f0f67b4788f967ee34f307312db302cecb68dd0b (patch) | |
tree | 90f207635e1c6a67aed11655e9e03b058c556665 | |
parent | 797486bc5f4d064821865c72425911994fa9fe22 (diff) | |
download | qtlocation-mapboxgl-f0f67b4788f967ee34f307312db302cecb68dd0b.tar.gz |
Add abs, round, floor, ceil operators (#11653)
* Add abs, round, floor, ceil operators
Port of https://github.com/mapbox/mapbox-gl-js/pull/6496
* [ios, macos] Simplified abs, ceiling, floor expressions
* [ios, macos] Added rounding expression function
* [android] - binding integration for round, ceil, floor and abs expressions
* Update mapbox-gl-js to include non-integer rounding test
* Drop extra braces
* mapbox-gl-js -> master
* Update style-spec docs -> PropertyFactory.java
11 files changed, 316 insertions, 32 deletions
diff --git a/mapbox-gl-js b/mapbox-gl-js -Subproject b01859294fec88111601028a539e45be1f08866 +Subproject 6b96d69ab54b149db1f6ef06daed37379ac0744 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 05c67018a4..fa4a802e13 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 @@ import java.util.List; * ) * } * </pre> - * */ public class Expression { @@ -1061,6 +1060,7 @@ public class Expression { * ); * } * </pre> + * * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-properties">Style specification</a> */ @@ -1081,6 +1081,7 @@ public class Expression { * ); * } * </pre> + * * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-geometry-types">Style specification</a> */ @@ -2295,6 +2296,185 @@ public class Expression { } /** + * Rounds the input to the nearest integer. + * Halfway values are rounded away from zero. + * For example `[\"round\", -1.5]` evaluates to -2. + * <p> + * Example usage: + * </p> + * <pre> + * {@code + * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id"); + * circleLayer.setProperties( + * circleRadius(round(pi())) + * ); + * } + * </pre> + * + * @param expression number expression to round + * @return expression + * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-round">Style specification</a> + */ + 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. + * <p> + * Example usage: + * </p> + * <pre> + * {@code + * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id"); + * circleLayer.setProperties( + * circleRadius(round(3.14159265359f)) + * ); + * } + * </pre> + * + * @param number number to round + * @return expression + * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-round">Style specification</a> + */ + public static Expression round(Number number) { + return round(literal(number)); + } + + /** + * Returns the absolute value of the input. + * <p> + * Example usage: + * </p> + * <pre> + * {@code + * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id"); + * circleLayer.setProperties( + * circleRadius(abs(subtract(pi()))) + * ); + * } + * </pre> + * + * @param expression number expression to get absolute value from + * @return expression + * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-abs">Style specification</a> + */ + public static Expression abs(Expression expression) { + return new Expression("abs", expression); + } + + /** + * Returns the absolute value of the input. + * <p> + * Example usage: + * </p> + * <pre> + * {@code + * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id"); + * circleLayer.setProperties( + * circleRadius(abs(-3.14159265359f)) + * ); + * } + * </pre> + * + * @param number number to get absolute value from + * @return expression + * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-abs">Style specification</a> + */ + public static Expression abs(Number number) { + return abs(literal(number)); + } + + /** + * Returns the smallest integer that is greater than or equal to the input. + * <p> + * Example usage: + * </p> + * <pre> + * {@code + * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id"); + * circleLayer.setProperties( + * circleRadius(ceil(pi())) + * ); + * } + * </pre> + * + * @param expression number expression to get value from + * @return expression + * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-abs">Style specification</a> + */ + public static Expression ceil(Expression expression) { + return new Expression("ceil", expression); + } + + /** + * Returns the smallest integer that is greater than or equal to the input. + * <p> + * Example usage: + * </p> + * <pre> + * {@code + * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id"); + * circleLayer.setProperties( + * circleRadius(ceil(3.14159265359)) + * ); + * } + * </pre> + * @param number number to get value from + * @return expression + * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-abs">Style specification</a> + */ + public static Expression ceil(Number number) { + return ceil(literal(number)); + } + + /** + * Returns the largest integer that is less than or equal to the input. + * <p> + * Example usage: + * </p> + * <pre> + * {@code + * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id"); + * circleLayer.setProperties( + * circleRadius(floor(pi())) + * ); + * } + * </pre> + * + * @param expression number expression to get value from + * @return expression + * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-abs">Style specification</a> + */ + public static Expression floor(Expression expression) { + return new Expression("floor", expression); + } + + /** + * Returns the largest integer that is less than or equal to the input. + * <p> + * Example usage: + * </p> + * <pre> + * {@code + * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id"); + * circleLayer.setProperties( + * circleRadius(floor(pi())) + * ); + * } + * </pre> + * + * @param number number to get value from + * @return expression + * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-abs">Style specification</a> + */ + public static Expression floor(Number number) { + return floor(literal(number)); + } + + /** * Returns the input string converted to uppercase. * <p> * Follows the Unicode Default Case Conversion algorithm @@ -3128,6 +3308,7 @@ public class Expression { * ); * } * </pre> + * * @param expression base number expression * @return expression * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-interpolate">Style specification</a> 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 66d78a40e5..4289deeda3 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 class PropertyFactory { } /** - * 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 class PropertyFactory { } /** - * 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 class PropertyFactory { } /** - * 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 class PropertyFactory { } /** - * 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 5694242a0a..45833e8556 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 org.junit.Test; 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.asin; 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.downcase; 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.product; 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 class ExpressionTest { ); 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 d61b292148..857d03d6e7 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 13204b09a6..1b8714811d 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 8c82c84c7d..6a61dd9abb 100644 --- a/platform/darwin/src/NSExpression+MGLAdditions.mm +++ b/platform/darwin/src/NSExpression+MGLAdditions.mm @@ -58,6 +58,7 @@ // 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:); @@ -84,6 +85,14 @@ } /** + 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. */ - (id)mgl_interpolate:(id)inputExpression withCurveType:(NSString *)curveType parameters:(NSDictionary *)params stops:(NSDictionary *)stops { @@ -487,6 +496,10 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { @"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 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { @"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 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { 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 579d2505f2..236c8d1ad9 100644 --- a/platform/darwin/test/MGLExpressionTests.mm +++ b/platform/darwin/test/MGLExpressionTests.mm @@ -393,29 +393,25 @@ using namespace std::string_literals; } { 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 @@ using namespace std::string_literals; } { 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 6b8839ecbe..87da59162e 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 8bd2e04d2b..e90858c664 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 77b294b380..c36ffa33e3 100644 --- a/src/mbgl/style/expression/compound_expression.cpp +++ b/src/mbgl/style/expression/compound_expression.cpp @@ -6,6 +6,7 @@ #include <mbgl/util/ignore.hpp> #include <mbgl/util/string.hpp> #include <mbgl/util/platform.hpp> +#include <cmath> namespace mbgl { namespace style { @@ -362,6 +363,11 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali return result; }); + define("round", [](double x) -> Result<double> { return std::round(x); }); + define("floor", [](double x) -> Result<double> { return std::floor(x); }); + define("ceil", [](double x) -> Result<double> { return std::ceil(x); }); + define("abs", [](double x) -> Result<double> { return std::abs(x); }); + define(">", [](double lhs, double rhs) -> Result<bool> { return lhs > rhs; }); define(">", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs > rhs; }); define(">=", [](double lhs, double rhs) -> Result<bool> { return lhs >= rhs; }); |