Allow predicates to test whether a feature lies within a given shape - #184
Conversation
| NSData *shapeData = [NSJSONSerialization dataWithJSONObject:object options:0 error:&error]; | ||
| MGLShape *shape; | ||
| if (shapeData && !error) { | ||
| shape = [MGLShape shapeWithData:shapeData encoding:NSUTF8StringEncoding error:&error]; |
There was a problem hiding this comment.
This works, but there may be a more efficient way to convert this JSON-like NSDictionary structure into an MGLShape. Perhaps we could first convert the NSDictionary structure into a C++ representation of the GeoJSON object, then convert to an MGLShape.
There was a problem hiding this comment.
Is there any performance considerations for bridging into an C++ object then back to MGLShape? Is this something that is going to be called frequently?
There was a problem hiding this comment.
In the current implementation, MGLStyleValueTransformer::PropertyExpressionEvaluator converts the C++ mapbox::geojson struct to a GeoJSON-formatted NSDictionary, then this method converts it to a string, then back to a C++ mapbox::geojson struct, then finally to an MGLShape object. It is more roundabout than it should be.
This conversion process happens once when setting a layer’s predicate or paint/layout property (which can happen automatically e.g. when localizing the style). mbgl will evaluate the already-converted expression on each feature, but no SDK-side code will run as part of the rendering loop.
Ideally, mbgl would preserve the mapbox::geojson struct so that MGLJSONObjectFromMBGLValue() could convert it directly to an MGLShape. Absent such a change in mbgl, there are two alternative, purely SDK-side approaches:
- Convert the NSDictionary directly to C++
mapbox::geojsonstructs then to MGLShape, skipping NSJSONSerialization - Parse the NSDictionary into an MGLShape, skipping C++
but I’m inclined to treat either optimization as tail work for when we know more about how this expression operator will be used. The performance characteristics could differ depending on the complexity of the passed-in GeoJSON feature.
|
@1ec5 will there be a developer-facing API that references |
The [NSPredicate predicateWithFormat:@"SELF IN %@", [MGLPolygon polygonWithCoodinates:coords count:4]];But if you’re referring to something more reminiscent of the JSON expression format, it’s also possible to use
The latter syntax is already possible without this PR, now that #183 has landed. I suppose we could install an aftermarket function like |
| `case` | `+[NSExpression expressionForConditional:trueExpression:falseExpression:]` or `MGL_IF` or `+[NSExpression mgl_expressionForConditional:trueExpression:falseExpresssion:]` | `TERNARY(1 = 2, YES, NO)` or `MGL_IF(1 = 2, YES, 2 = 2, YES, NO)` | ||
| `coalesce` | `mgl_coalesce:` | `mgl_coalesce({x, y, z})` | ||
| `match` | `MGL_MATCH` or `+[NSExpression mgl_expressionForMatchingExpression:inDictionary:defaultExpression:]` | `MGL_MATCH(x, 0, 'zero match', 1, 'one match', 'two match', 'default')` | ||
| `within` | `NSInPredicateOperatorType` | `SELF IN %@` or `%@ CONTAINS SELF` where `%@` is an `MGLShape` |
There was a problem hiding this comment.
As always, if a developer is already familiar with the style specification’s JSON expression format or a similar syntax on Android, they can consult the “Information for Style Authors” guide to learn the corresponding NSExpression syntax.
|
Per #175 (comment), MGLConversion needs to convert from mapbox-gl-native-ios/platform/darwin/src/MGLConversion.h Lines 127 to 130 in 534d64c This code is called as part of |
julianrex
left a comment
There was a problem hiding this comment.
Thanks! Just the question from @fabian-guerra
fabian-guerra
left a comment
There was a problem hiding this comment.
I agree that we could treat optimizations as tail work. Thank you for explaining. LGTM in that case.
534d64c to
aa95fdb
Compare
|
As of 11424ded73745e734c2d1f58b9fad8d7bd8ae635, the Debug ‣ Manipulate Style command adds a circle layer that should mark each POI around here. However, nothing shows up because the
As far as I can tell, the SDK code is behaving correctly and the shape is valid, but the expression never evaluates to true. I’ve also tried reversing the polygon and removing the closing point to no avail. /cc @zmiao |
There was a problem hiding this comment.
MGLFeature support was added in mapbox/mapbox-gl-native#16232, which we haven’t pulled into this repository yet.
I’ve confirmed that this will also be fixed by mapbox/mapbox-gl-native#16232 once we pull it in. |
#210 will pull in the fix. No additional changes are needed for |
11424de to
d4041d2
Compare
Fixed an issue where GeoJSON geometries were converted to MGLFeature instances instead of MGLShape objects.
d4041d2 to
9e28d66
Compare
Added support for the expression syntax “SELF IN shape” or “shape CONTAINS SELF”, which is interpreted as a “within” expression in JSON format.
9e28d66 to
e27b889
Compare


Added support for the NSPredicate syntax
SELF IN shapeorshape CONTAINS SELF, whereshapeis an MGLShape object or MGLFeature instance. These syntaxes are interpreted aswithinexpressions in JSON format.Fixed an issue where GeoJSON geometries were converted to MGLFeature instances instead of MGLShape objects. This issue probably hasn’t come up in the wild because the conversion code was previously only part of a feature querying code path, and feature querying methods return features anyways. But since it’s possible for the
shapeinSELF IN shapeto be an MGLShape, that shape should get round-tripped as an MGLShape rather than an MGLFeature.Fixes #175. Depends on #183, which in turn depends on #181. Retarget and rebase this PR onto master before merging.
/cc @mapbox/maps-ios