-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Conversation
@ivovandongen, thanks for your PR! By analyzing this pull request, we identified @jfirebaugh, @1ec5 and @incanus to be potential reviewers. |
bc88add
to
d3616d2
Compare
include/mbgl/map/map.hpp
Outdated
@@ -3,6 +3,7 @@ | |||
#include <mbgl/util/optional.hpp> | |||
#include <mbgl/util/chrono.hpp> | |||
#include <mbgl/map/mode.hpp> | |||
#include <mbgl/map/query.hpp> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already included below.
include/mbgl/map/query.hpp
Outdated
class SourceQueryOptions { | ||
public: | ||
// Required for VectorSource, ignored for GeoJSONSource | ||
optional<std::string> sourceLayer; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make this a std::vector<std::string>
like RenderedQueryOptions
. I don't think there's a good reason that the GL JS API is inconsistent (mapbox/mapbox-gl-js#4372).
include/mbgl/map/map.hpp
Outdated
AnnotationIDs queryPointAnnotations(const ScreenBox&); | ||
std::vector<Feature> querySourceFeatures(const std::string&, const SourceQueryOptions& options = {}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GL native exposes an object-oriented API for sources -- move this method to mbgl::style::Source
, rename it to queryFeatures
, and drop the first parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jfirebaugh This does mean that you have to retrieve the source in the SDKs before querying. Small overhead, but still. Is this what we want?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jfirebaugh In this case; shall I move SourceQueryOptions to a separate header in the mbgl::style
namespace? or keep it here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does mean that you have to retrieve the source in the SDKs before querying. Small overhead, but still. Is this what we want?
Yes, I think so -- by eliminating the map
middleman in map.querySourceFeatures(source)
, source.queryFeatures()
becomes conceptually simpler and possibly actually more efficient in the case of repeated queries (though I would indeed expect the benefit to be negligible).
shall I move SourceQueryOptions to a separate header in the
mbgl::style
namespace?
Yeah, I think that makes sense.
fa9c52e
to
46c655e
Compare
I've been thinking about making the same change to the iOS/macOS SDKs' public API for queryRenderedFeatures: accept an array of MGLStyleLayers instead of an array of identifiers in an awkwardly named parameter. The overhead is negligible for moderately complex styles. macosapp, for instance, retrieves and wraps every style layer on load, and any performance impact seems reasonable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sweet – this will unblock plenty of use cases, plus some improvements I've been meaning to make around VoiceOver accessibility support.
In addition to the comments below, please add an entry to the iOS and macOS changelogs. Thanks!
platform/ios/src/MGLMapView.h
Outdated
@return An array of objects conforming to the `MGLFeature` protocol that | ||
represent features in the sources used by the current style. | ||
*/ | ||
- (NS_ARRAY_OF(id <MGLFeature>) *)featuresWithSourceIdentifier:(NSString *)sourceIdentifier sourceLayerIdentifier:(nullable NSString *)sourceLayerIdentifier predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(features(sourceIdentifier:sourceLayerIdentifier:predicate:)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about -featuresLoadedInSource:sourceLayerIdentifier:predicate:
?
Especially if this method only works with a single source at a time, I think it would be desirable to require the developer to pass in an MGLSource object instead of a source identifier. That encourages the developer to obtain an existing source and helps to clarify the distinction between a source identifier and a source layer identifier.
Additionally, we probably want to emphasize that this method returns the features that have already loaded, not all the possible features in the source (which for a vector source could be quite unwieldy). This isn't quite a reverse geocoding API, after all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-featuresLoadedBySource:sourceLayerIdentifier:predicate:
would avoid overusing "in", especially if we later add a bounding box option.
Swift can probably come up with a decent name for this method without the NS_SWIFT_NAME
attribute. (Try it out locally by trying to call the method in one of our Swift unit test files.) If not, try providing a Swift name of features(loadedBy:sourceLayerIdentifier:predicate:)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll want to push the change suggested above (moving the query method to the Source
object itself) out to the SDK level, making this -[MGLSource featuresLoaded:inLayerWithIdentifier:predicate:]
or similar.
platform/ios/src/MGLMapView.h
Outdated
Features come from tiled vector data or GeoJSON data that is converted to tiles | ||
internally, so feature geometries are clipped at tile boundaries and features | ||
may appear duplicated across tiles. For example, suppose the specified | ||
rectangle intersects with a road that spans the screen. The resulting array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some of this explanation is specific to -visibleFeaturesInRect:. This method by contrast accepts no rectangle parameter.
2b1e017
to
3f742a9
Compare
platform/darwin/src/MGLShapeSource.h
Outdated
Features come from tiled vector data or GeoJSON data that is converted to tiles | ||
internally, so feature geometries are clipped at tile boundaries and features | ||
may appear duplicated across tiles. For example, suppose the specified | ||
rectangle intersects with a road that spans the screen. The resulting array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No rectangle is specified as part of this API.
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL NS_DESIGNATED_INITIALIZER; | ||
|
||
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options NS_DESIGNATED_INITIALIZER; | ||
|
||
#pragma mark Querying the source's features |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since jazzy uses mark
s to generate section headings, it’s important to keep them consistent (title case, describes a task, uses the most commonplace terms possible). How about “Accessing a Source’s Content”, which is the same mark
we use in MGLShapeSource?
platform/darwin/src/MGLShapeSource.h
Outdated
@@ -210,6 +210,31 @@ MGL_EXPORT | |||
*/ | |||
@property (nonatomic, copy, nullable) NSURL *URL; | |||
|
|||
#pragma mark Querying the source's features |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think -featuresMatchingPredicate:
falls neatly under the existing “Accessing a Source’s Content” section heading.
platform/darwin/src/MGLShapeSource.h
Outdated
@return An array of objects conforming to the `MGLFeature` protocol that | ||
represent features in the sources used by the current style. | ||
*/ | ||
- (NS_ARRAY_OF(id <MGLFeature>) *)featuresWithPredicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(features(predicate:)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call this method -featuresMatchingPredicate:
and remove the NS_SWIFT_NAME
attribute. Swift will automatically bridge it as features(matching:)
.
The convention in Swift 3 is for argument labels to be prepositions or participles like “matching” instead of prepositional objects like “predicate”. matching:
would be more intuitive argument label than with:
in this case. (It’d also be consistent with methods like -[CNContactStore groupsMatchingPredicate:error:]
, -[EKEventStore eventsMatchingPredicate:]
, and -[XCUIElementQuery matchingPredicate:]
in standard Apple libraries.)
platform/darwin/src/MGLShapeSource.h
Outdated
current style and provides access to attributes specified by the relevant | ||
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile sources</a>. | ||
The returned array includes features specified in vector and GeoJSON tile | ||
sources but does not include anything from raster, image, or video sources. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that this method lives on MGLShapeSource, it’s unnecessary to point out that it won’t return features from non-shape sources. It’s also important to note that this method may return features that exist in the source but are not currently drawn by a style layer.
current style and provides access to attributes specified by the relevant | ||
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile sources</a>. | ||
The returned array includes features specified in vector and GeoJSON tile | ||
sources but does not include anything from raster, image, or video sources. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, there’s no need here to talk about other sources.
the road within each map tile is included individually. | ||
|
||
@param sourceLayerIdentifiers The source layers to include in the query. Only the | ||
features contained in this source layers are included in the returned array. At |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/this source layers/these source layers/
least one source layer is required. | ||
@param predicate A predicate to filter the returned features. | ||
@return An array of objects conforming to the `MGLFeature` protocol that | ||
represent features in the sources used by the current style. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any significance to the order in which the features are returned? (It’s fine if there isn’t; we may even want to leave the order unmentioned as wiggle room for future improvements.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, not any order in particular and I don't think we should make any guarantees for now. Right now the order is sourceLayer, feature index.
#pragma mark Querying the source's features | ||
|
||
/** | ||
Returns an array of map features for this source, restricted to the given |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/for this source/loaded by this source/
XCTAssertNotNil(mapView.style); | ||
XCTAssertEqual(mapView.style, style); | ||
|
||
[_styleLoadingExpectation fulfill]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case you’re wondering why this works for shape sources but not vector sources, -mapView:didFinishLoadingStyle:
gets called as soon as we’re done loading and parsing the style itself. It isn’t guaranteed that all sources load by this point. If you wanted to query a vector source too, you’d need to wait until -mapViewDidFinishLoadingMap:
is called. But this is perfectly fine for the inline GeoJSON sources in query-style.json, since they load as part of the style.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you wanted to query a vector source too, you’d need to wait until -mapViewDidFinishLoadingMap: is called
I've tried this, but this callback is never fired in this setup.
this is perfectly fine for the inline GeoJSON sources in query-style.json, since they load as part of the style.
I expected the same, but the inline geojson sources also don't seem to load this way.
4c1aadc
to
4219e26
Compare
@jfirebaugh Made the changes you requested and adapted the SDK bindings. Adding support for multiple sourceLayers resulted in some code duplication in: GeoJSONTile:: querySourceFeatures. Could extract the common functionality, not sure if it's worth it. |
4219e26
to
5e8da5e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested the Android sample and getting 4 features when clicking the map. Android side of things looks good to 🚢
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple documentation nits, but the iOS/macOS changes are 👌 otherwise.
platform/darwin/src/MGLShapeSource.h
Outdated
|
||
Each object in the returned array represents a feature for the | ||
current style and provides access to attributes specified by the | ||
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">source</a>. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There’s also no need to link “source”, since this method lives inside an MGLSource subclass.
#pragma mark Accessing a Source’s Content | ||
|
||
/** | ||
Returns an array of map features for this source, restricted to the given |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reminder: s/for this source/loaded by this source/
may appear duplicated across tiles. | ||
|
||
@param sourceLayerIdentifiers The source layers to include in the query. Only the | ||
features contained in this source layers are included in the returned array. At |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reminder: s/this source layers/these source layers/
5e8da5e
to
3f72b72
Compare
3f72b72
to
42b76cd
Compare
Fixes #5792