diff options
23 files changed, 1265 insertions, 110 deletions
diff --git a/platform/darwin/src/MGLFeature.h b/platform/darwin/src/MGLFeature.h new file mode 100644 index 0000000000..389b8ab67f --- /dev/null +++ b/platform/darwin/src/MGLFeature.h @@ -0,0 +1,164 @@ +#import <Foundation/Foundation.h> + +#import "MGLPolyline.h" +#import "MGLPolygon.h" +#import "MGLPointAnnotation.h" +#import "MGLShapeCollection.h" + +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + The `MGLFeature` protocol is used to provide details about geographic features + contained in a map view’s + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile sources</a>. + Each concrete subclass of `MGLShape` in turn has a subclass that conforms to + this protocol. + + Typically, you do not create feature objects yourself but rather obtain them + using `-[MGLMapView visibleFeaturesAtPoint:]` and related methods. Each feature + object associates a shape with an identifier and attributes as specified by the + source. Like any `MGLAnnotation` object, an `MGLFeature` object can be added to + a map view using `-[MGLMapView addAnnotations:]` and related methods. + */ +@protocol MGLFeature <MGLAnnotation> + +/** + An object that uniquely identifies the feature in its containing + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>. + + The value of this property is currently always an `NSNumber` object but may in + the future be an instance of another class, such as `NSString`. + + The identifier corresponds to the + <a href="https://github.com/mapbox/vector-tile-spec/tree/master/2.1#42-features">feature identifier</a> + (`id`) in the tile source. If the source does not specify the feature’s + identifier, the value of this property is `nil`. + + For details about the identifiers used in most Mapbox-provided styles, consult + the + <a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets</a> + layer reference. + */ +@property (nonatomic, copy, nullable, readonly) id identifier; + +/** + A dictionary of attributes for this feature specified by the + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>. + + The keys and values of this dictionary are determined by the tile source. In + the tile source, each attribute name is a string, while each attribute value + may be a null value, Boolean value, integer, floating-point number, or string. + These data types are mapped to instances of the following Foundation classes: + + <table> + <thead> + <tr><th>In the tile source</th><th>In this dictionary</th></tr> + </thead> + <tbody> + <tr><td>Null</td> <td><code>NSNull</code></td></tr> + <tr><td>Boolean</td> <td><code>NSNumber</code> (use the <code>boolValue</code> property)</td></tr> + <tr><td>Integer</td> <td><code>NSNumber</code> (use the <code>unsignedLongLongValue</code> or <code>longLongValue</code> property)</td></tr> + <tr><td>Floating-point number</td> <td><code>NSNumber</code> (use the <code>doubleValue</code> property)</td></tr> + <tr><td>String</td> <td><code>NSString</code></td></tr> + </tbody> + </table> + + For details about the attribute names and values found in Mapbox-provided + vector tile sources, consult the + <a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets</a> + and + <a href="https://www.mapbox.com/vector-tiles/mapbox-terrain/">Mapbox Terrain</a> + layer references. + */ +@property (nonatomic, copy, readonly) NS_DICTIONARY_OF(NSString *, id) *attributes; + +/** + Returns the feature attribute for the given attribute name. + + See the `attributes` property’s documentation for details on keys and values + associated with this method. + */ +- (nullable id)attributeForKey:(NSString *)key; + +@end + +/** + The `MGLPointFeature` class represents a point in a + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>. + */ +@interface MGLPointFeature : MGLPointAnnotation <MGLFeature> + +@property (nonatomic, copy, nullable, readwrite) id identifier; +@property (nonatomic, copy, readwrite) NS_DICTIONARY_OF(NSString *, id) *attributes; + +@end + +/** + The `MGLPolylineFeature` class represents a polyline in a + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>. + */ +@interface MGLPolylineFeature : MGLPolyline <MGLFeature> + +@property (nonatomic, copy, nullable, readwrite) id identifier; +@property (nonatomic, copy, readwrite) NS_DICTIONARY_OF(NSString *, id) *attributes; + +@end + +/** + The `MGLPolygonFeature` class represents a polygon in a + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>. + */ +@interface MGLPolygonFeature : MGLPolygon <MGLFeature> + +@property (nonatomic, copy, nullable, readwrite) id identifier; +@property (nonatomic, copy, readwrite) NS_DICTIONARY_OF(NSString *, id) *attributes; + +@end + +/** + The `MGLMultiPointFeature` class represents a multipoint in a + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>. + */ +@interface MGLMultiPointFeature : MGLMultiPoint <MGLFeature> + +@property (nonatomic, copy, nullable, readwrite) id identifier; +@property (nonatomic, copy, readwrite) NS_DICTIONARY_OF(NSString *, id) *attributes; + +@end + +/** + The `MGLMultiPolylineFeature` class represents a multipolyline in a + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>. + */ +@interface MGLMultiPolylineFeature : MGLMultiPolyline <MGLFeature> + +@property (nonatomic, copy, nullable, readwrite) id identifier; +@property (nonatomic, copy, readwrite) NS_DICTIONARY_OF(NSString *, id) *attributes; + +@end + +/** + The `MGLMultiPolygonFeature` class represents a multipolygon in a + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>. + */ +@interface MGLMultiPolygonFeature : MGLMultiPolygon <MGLFeature> + +@property (nonatomic, copy, nullable, readwrite) id identifier; +@property (nonatomic, copy, readwrite) NS_DICTIONARY_OF(NSString *, id) *attributes; + +@end + +/** + The `MGLShapeCollectionFeature` class represents a shape collection in a + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>. + */ +@interface MGLShapeCollectionFeature : MGLShapeCollection <MGLFeature> + +@property (nonatomic, copy, nullable, readwrite) id identifier; +@property (nonatomic, copy, readwrite) NS_DICTIONARY_OF(NSString *, id) *attributes; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm new file mode 100644 index 0000000000..68c57a193a --- /dev/null +++ b/platform/darwin/src/MGLFeature.mm @@ -0,0 +1,244 @@ +#import "MGLFeature_Private.h" + +#import "MGLPointAnnotation.h" +#import "MGLPolyline.h" +#import "MGLPolygon.h" + +#import "MGLMultiPoint_Private.h" + +class PropertyValueEvaluator { +public: + PropertyValueEvaluator() {} + + id operator()(const std::nullptr_t &) const { + return [NSNull null]; + } + + id operator()(const bool &value) const { + return value ? @YES : @NO; + } + + id operator()(const uint64_t &value) const { + return @(value); + } + + id operator()(const int64_t &value) const { + return @(value); + } + + id operator()(const double &value) const { + return @(value); + } + + id operator()(const std::string &value) const { + return @(value.c_str()); + } + + id operator()(const std::vector<mbgl::Value> &values) const { + std::vector<id> objects; + objects.reserve(values.size()); + std::transform(values.begin(), values.end(), std::back_inserter(objects), ^id (const mbgl::Value &value) { + PropertyValueEvaluator evaluator; + return mbgl::Value::visit(value, evaluator); + }); + return [NSArray arrayWithObjects:&objects[0] count:objects.size()]; + } + + id operator()(const std::unordered_map<std::string, mbgl::Value> &items) const { + std::vector<NSString *> keys; + keys.reserve(items.size()); + std::vector<id> objects; + objects.reserve(items.size()); + for (auto &item : items) { + keys.push_back(@(item.first.c_str())); + PropertyValueEvaluator evaluator; + objects.push_back(mbgl::Value::visit(item.second, evaluator)); + } + return [NSDictionary dictionaryWithObjects:&objects[0] forKeys:&keys[0] count:keys.size()]; + } +}; + +template <typename T> +class GeometryEvaluator { +public: + GeometryEvaluator() + : attributes([NSMutableDictionary dictionary]) {} + + GeometryEvaluator(const mbgl::Feature &feature) + : tag(feature.id ? @(*feature.id) : nullptr), + attributes([NSMutableDictionary dictionaryWithCapacity:feature.properties.size()]) { + for (auto &pair : feature.properties) { + auto &value = pair.second; + PropertyValueEvaluator evaluator; + attributes[@(pair.first.c_str())] = mbgl::Value::visit(value, evaluator); + } + } + + MGLShape <MGLFeature> * operator()(const mapbox::geometry::point<T> &geometry) const { + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + feature.coordinate = coordinateFromPoint(geometry); + feature.identifier = tag; + feature.attributes = attributes; + return feature; + } + + MGLShape <MGLFeature> * operator()(const mapbox::geometry::line_string<T> &geometry) const { + std::vector<CLLocationCoordinate2D> coordinates; + coordinates.reserve(geometry.size()); + std::transform(geometry.begin(), geometry.end(), std::back_inserter(coordinates), coordinateFromPoint); + + MGLPolylineFeature *feature = [[MGLPolylineFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()]; + feature.identifier = tag; + feature.attributes = attributes; + return feature; + } + + MGLShape <MGLFeature> * operator()(const mapbox::geometry::polygon<T> &geometry) const { + // TODO: MGLPolygon doesn’t support holes, so what to do? + auto &linearRing = geometry.front(); + + std::vector<CLLocationCoordinate2D> coordinates; + coordinates.reserve(linearRing.size()); + std::transform(linearRing.begin(), linearRing.end(), std::back_inserter(coordinates), coordinateFromPoint); + + MGLPolygonFeature *feature = [[MGLPolygonFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()]; + feature.identifier = tag; + feature.attributes = attributes; + return feature; + } + + MGLShape <MGLFeature> * operator()(const mapbox::geometry::multi_point<T> &geometry) const { + std::vector<CLLocationCoordinate2D> coordinates; + coordinates.reserve(geometry.size()); + std::transform(geometry.begin(), geometry.end(), std::back_inserter(coordinates), coordinateFromPoint); + + MGLMultiPointFeature *feature = [[MGLMultiPointFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()]; + feature.identifier = tag; + feature.attributes = attributes; + return feature; + } + + MGLShape <MGLFeature> * operator()(const mapbox::geometry::multi_line_string<T> &geometry) const { + NSMutableArray *polylines = [NSMutableArray arrayWithCapacity:geometry.size()]; + for (auto &lineString : geometry) { + std::vector<CLLocationCoordinate2D> coordinates; + coordinates.reserve(lineString.size()); + std::transform(lineString.begin(), lineString.end(), std::back_inserter(coordinates), coordinateFromPoint); + + MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:&coordinates[0] count:coordinates.size()]; + [polylines addObject:polyline]; + } + + MGLMultiPolylineFeature *feature = [MGLMultiPolylineFeature multiPolylineWithPolylines:polylines]; + feature.identifier = tag; + feature.attributes = attributes; + return feature; + } + + MGLShape <MGLFeature> * operator()(const mapbox::geometry::multi_polygon<T> &geometry) const { + NSMutableArray *polygons = [NSMutableArray arrayWithCapacity:geometry.size()]; + for (auto &polygon : geometry) { + // TODO: MGLPolygon doesn’t support holes, so what to do? + auto &linearRing = polygon.front(); + + std::vector<CLLocationCoordinate2D> coordinates; + coordinates.reserve(linearRing.size()); + std::transform(linearRing.begin(), linearRing.end(), std::back_inserter(coordinates), coordinateFromPoint); + + MGLPolygon *polygonObject = [MGLPolygon polygonWithCoordinates:&coordinates[0] count:coordinates.size()]; + [polygons addObject:polygonObject]; + } + + MGLMultiPolygonFeature *feature = [MGLMultiPolygonFeature multiPolygonWithPolygons:polygons]; + feature.identifier = tag; + feature.attributes = attributes; + return feature; + } + + MGLShape <MGLFeature> * operator()(const mapbox::geometry::geometry_collection<T> &collection) const { + NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:collection.size()]; + for (auto &geometry : collection) { + GeometryEvaluator<T> evaluator; + id <MGLFeature> feature = mapbox::geometry::geometry<T>::visit(geometry, evaluator); + [shapes addObject:feature]; + } + MGLShapeCollectionFeature *feature = [MGLShapeCollectionFeature shapeCollectionWithShapes:shapes]; + feature.identifier = tag; + feature.attributes = attributes; + return feature; + } + +private: + NSNumber *tag = nullptr; + NS_MUTABLE_DICTIONARY_OF(NSString *, id) *attributes; + + static CLLocationCoordinate2D coordinateFromPoint(const mapbox::geometry::point<T> &point) { + return CLLocationCoordinate2DMake(point.y, point.x); + } +}; + +NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features) { + std::vector<MGLShape <MGLFeature> *> shapes; + shapes.reserve(features.size()); + std::transform(features.begin(), features.end(), std::back_inserter(shapes), ^MGLShape <MGLFeature> * (const mbgl::Feature &feature) { + GeometryEvaluator<double> evaluator(feature); + return mapbox::geometry::geometry<double>::visit(feature.geometry, evaluator); + }); + return [NSArray arrayWithObjects:&shapes[0] count:shapes.size()]; +} + +@implementation MGLPointFeature + +- (id)attributeForKey:(NSString *)key { + return self.attributes[key]; +} + +@end + +@implementation MGLPolylineFeature + +- (id)attributeForKey:(NSString *)key { + return self.attributes[key]; +} + +@end + +@implementation MGLPolygonFeature + +- (id)attributeForKey:(NSString *)key { + return self.attributes[key]; +} + +@end + +@implementation MGLMultiPointFeature + +- (id)attributeForKey:(NSString *)key { + return self.attributes[key]; +} + +@end + +@implementation MGLMultiPolylineFeature + +- (id)attributeForKey:(NSString *)key { + return self.attributes[key]; +} + +@end + +@implementation MGLMultiPolygonFeature + +- (id)attributeForKey:(NSString *)key { + return self.attributes[key]; +} + +@end + +@implementation MGLShapeCollectionFeature + +- (id)attributeForKey:(NSString *)key { + return self.attributes[key]; +} + +@end diff --git a/platform/darwin/src/MGLFeature_Private.h b/platform/darwin/src/MGLFeature_Private.h new file mode 100644 index 0000000000..837461871e --- /dev/null +++ b/platform/darwin/src/MGLFeature_Private.h @@ -0,0 +1,7 @@ +#import "MGLFeature.h" +#import "MGLShape.h" + +#import <mbgl/util/geo.hpp> +#import <mbgl/util/feature.hpp> + +NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features); diff --git a/platform/darwin/src/MGLPolygon.h b/platform/darwin/src/MGLPolygon.h index 1a158874bb..a12e62b106 100644 --- a/platform/darwin/src/MGLPolygon.h +++ b/platform/darwin/src/MGLPolygon.h @@ -30,4 +30,28 @@ NS_ASSUME_NONNULL_BEGIN @end +/** + The `MGLMultiPolygon` class represents a shape consisting of one or more + polygons that do not overlap. For example, you would use an `MGLMultiPolygon` + object to represent an atoll together with an island in the atoll’s lagoon: + the atoll itself would be one `MGLPolygon` object, while the inner island would + be another. + */ +@interface MGLMultiPolygon : MGLShape <MGLOverlay> + +/** + An array of polygons forming the multipolygon. + */ +@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLPolygon *) *polygons; + +/** + Creates and returns a multipolygon object consisting of the given polygons. + + @param polygons The array of polygons defining the shape. + @return A new multipolygon object. + */ ++ (instancetype)multiPolygonWithPolygons:(NS_ARRAY_OF(MGLPolygon *) *)polygons; + +@end + NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm index 5019385cb2..6febf6d81b 100644 --- a/platform/darwin/src/MGLPolygon.mm +++ b/platform/darwin/src/MGLPolygon.mm @@ -1,6 +1,7 @@ #import "MGLPolygon.h" #import "MGLMultiPoint_Private.h" +#import "MGLGeometry_Private.h" @implementation MGLPolygon @@ -26,3 +27,39 @@ } @end + +@interface MGLMultiPolygon () + +@property (nonatomic, copy, readwrite) NS_ARRAY_OF(MGLPolygon *) *polygons; + +@end + +@implementation MGLMultiPolygon { + MGLCoordinateBounds _overlayBounds; +} + +@synthesize overlayBounds = _overlayBounds; + ++ (instancetype)multiPolygonWithPolygons:(NS_ARRAY_OF(MGLPolygon *) *)polygons { + return [[self alloc] initWithPolygons:polygons]; +} + +- (instancetype)initWithPolygons:(NS_ARRAY_OF(MGLPolygon *) *)polygons { + if (self = [super init]) { + _polygons = polygons; + + mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty(); + + for (MGLPolygon *polygon in _polygons) { + bounds.extend(MGLLatLngBoundsFromCoordinateBounds(polygon.overlayBounds)); + } + _overlayBounds = MGLCoordinateBoundsFromLatLngBounds(bounds); + } + return self; +} + +- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds { + return MGLLatLngBoundsFromCoordinateBounds(_overlayBounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds)); +} + +@end diff --git a/platform/darwin/src/MGLPolyline.h b/platform/darwin/src/MGLPolyline.h index 5e45513735..a453a43a41 100644 --- a/platform/darwin/src/MGLPolyline.h +++ b/platform/darwin/src/MGLPolyline.h @@ -30,4 +30,28 @@ NS_ASSUME_NONNULL_BEGIN @end +/** + The `MGLMultiPolyline` class represents a shape consisting of one or more + polylines. For example, you could use an `MGLMultiPolyline` object to represent + both sides of a divided highway (dual carriageway), excluding the median + (central reservation): each carriageway would be a distinct `MGLPolyline` + object. + */ +@interface MGLMultiPolyline : MGLShape <MGLOverlay> + +/** + An array of polygons forming the multipolyline. + */ +@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLPolyline *) *polylines; + +/** + Creates and returns a multipolyline object consisting of the given polylines. + + @param polylines The array of polylines defining the shape. + @return A new multipolyline object. + */ ++ (instancetype)multiPolylineWithPolylines:(NS_ARRAY_OF(MGLPolyline *) *)polylines; + +@end + NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm index f560a571bc..810b359bb0 100644 --- a/platform/darwin/src/MGLPolyline.mm +++ b/platform/darwin/src/MGLPolyline.mm @@ -1,6 +1,7 @@ #import "MGLPolyline.h" #import "MGLMultiPoint_Private.h" +#import "MGLGeometry_Private.h" @implementation MGLPolyline @@ -26,3 +27,39 @@ } @end + +@interface MGLMultiPolyline () + +@property (nonatomic, copy, readwrite) NS_ARRAY_OF(MGLPolyline *) *polylines; + +@end + +@implementation MGLMultiPolyline { + MGLCoordinateBounds _overlayBounds; +} + +@synthesize overlayBounds = _overlayBounds; + ++ (instancetype)multiPolylineWithPolylines:(NS_ARRAY_OF(MGLPolyline *) *)polylines { + return [[self alloc] initWithPolylines:polylines]; +} + +- (instancetype)initWithPolylines:(NS_ARRAY_OF(MGLPolyline *) *)polylines { + if (self = [super init]) { + _polylines = polylines; + + mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty(); + + for (MGLPolyline *polyline in _polylines) { + bounds.extend(MGLLatLngBoundsFromCoordinateBounds(polyline.overlayBounds)); + } + _overlayBounds = MGLCoordinateBoundsFromLatLngBounds(bounds); + } + return self; +} + +- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds { + return MGLLatLngBoundsFromCoordinateBounds(_overlayBounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds)); +} + +@end diff --git a/platform/darwin/src/MGLShapeCollection.h b/platform/darwin/src/MGLShapeCollection.h new file mode 100644 index 0000000000..f4dc226228 --- /dev/null +++ b/platform/darwin/src/MGLShapeCollection.h @@ -0,0 +1,32 @@ +#import <Foundation/Foundation.h> + +#import "MGLShape.h" + +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + The `MGLShapeCollection` class represents a shape consisting of one or more + distinct but related shapes that are instances of `MGLShape`. The constituent + shapes can be a mixture of different kinds of shapes. + */ +@interface MGLShapeCollection : MGLShape + +/** + An array of shapes forming the shape collection. + */ +@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLShape <MGLAnnotation> *) *shapes; + +/** + Creates and returns a shape collection consisting of the given shapes. + + @param shapes The array of shapes defining the shape collection. The data in + this array is copied to the new object. + @return A new shape collection object. + */ ++ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape <MGLAnnotation> *) *)shapes; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLShapeCollection.m b/platform/darwin/src/MGLShapeCollection.m new file mode 100644 index 0000000000..3fc4cdda75 --- /dev/null +++ b/platform/darwin/src/MGLShapeCollection.m @@ -0,0 +1,21 @@ +#import "MGLShapeCollection.h" + +@implementation MGLShapeCollection + ++ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape <MGLAnnotation> *) *)shapes { + return [[self alloc] initWithShapes:shapes]; +} + +- (instancetype)initWithShapes:(NS_ARRAY_OF(MGLShape <MGLAnnotation> *) *)shapes { + if (self = [super init]) { + NSAssert(shapes.count, @"Cannot create an empty shape collection"); + _shapes = shapes.copy; + } + return self; +} + +- (CLLocationCoordinate2D)coordinate { + return _shapes.firstObject.coordinate; +} + +@end diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 012688ab17..0754aa2a0d 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -10,6 +10,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CON - The user dot now moves smoothly between user location updates while user location tracking is disabled. ([#1582](https://github.com/mapbox/mapbox-gl-native/pull/1582)) - An MGLAnnotation can be relocated by changing its `coordinate` property in a KVO-compliant way. An MGLMultiPoint cannot be relocated. ([#3835](https://github.com/mapbox/mapbox-gl-native/pull/3835)) - Setting the `image` property of an MGLAnnotationImage to `nil` resets it to the default red pin image and reclaims resources that can be used to customize additional annotations. ([#3835](https://github.com/mapbox/mapbox-gl-native/pull/3835)) +- Added methods to MGLMapView for obtaining the underlying map data rendered by the current style. ([#5110](https://github.com/mapbox/mapbox-gl-native/pull/5110)) - `MGLOfflinePackProgress` now indicates how many tiles have been downloaded and how much space they take up. ([#4874](https://github.com/mapbox/mapbox-gl-native/pull/4874)) - The compass, user dot, and visible annotations are now accessible to VoiceOver users. ([#1496](https://github.com/mapbox/mapbox-gl-native/pull/1496)) - The SDK is now localizable. No localizations are currently provided, other than English, but if you need a particular localization, you can install the SDK manually and drop a .lproj folder into the framework. ([#4783](https://github.com/mapbox/mapbox-gl-native/pull/4783)) diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index 13b4fbffec..2f5aacfe6c 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -395,13 +395,22 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie { if (longPress.state == UIGestureRecognizerStateBegan) { - MBXDroppedPinAnnotation *point = [[MBXDroppedPinAnnotation alloc] init]; - point.coordinate = [self.mapView convertPoint:[longPress locationInView:longPress.view] + CGPoint point = [longPress locationInView:longPress.view]; + NSArray *features = [self.mapView visibleFeaturesAtPoint:point]; + NSString *title; + for (id <MGLFeature> feature in features) { + if (!title) { + title = [feature attributeForKey:@"name_en"] ?: [feature attributeForKey:@"name"]; + } + } + + MBXDroppedPinAnnotation *pin = [[MBXDroppedPinAnnotation alloc] init]; + pin.coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView]; - point.title = @"Dropped Pin"; - point.subtitle = [[[MGLCoordinateFormatter alloc] init] stringFromCoordinate:point.coordinate]; + pin.title = title ?: @"Dropped Pin"; + pin.subtitle = [[[MGLCoordinateFormatter alloc] init] stringFromCoordinate:pin.coordinate]; // Calling `addAnnotation:` on mapView is not required since `selectAnnotation:animated` has the side effect of adding the annotation if required - [self.mapView selectAnnotation:point animated:YES]; + [self.mapView selectAnnotation:pin animated:YES]; } } diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index cf48b869e3..3f233441f7 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -228,6 +228,15 @@ DABFB8731CBE9A9900D62B32 /* Mapbox.h in Headers */ = {isa = PBXBuildFile; fileRef = DA88485E1CBAFC2E00AB86E3 /* Mapbox.h */; settings = {ATTRIBUTES = (Public, ); }; }; DAC49C5C1CD02BC9009E1AA3 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DAC49C5F1CD02BC9009E1AA3 /* Localizable.stringsdict */; }; DAC49C5D1CD02BC9009E1AA3 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DAC49C5F1CD02BC9009E1AA3 /* Localizable.stringsdict */; }; + DAD1656C1CF41981001FF4B9 /* MGLFeature.h in Headers */ = {isa = PBXBuildFile; fileRef = DAD165691CF41981001FF4B9 /* MGLFeature.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAD1656D1CF41981001FF4B9 /* MGLFeature.h in Headers */ = {isa = PBXBuildFile; fileRef = DAD165691CF41981001FF4B9 /* MGLFeature.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAD1656E1CF41981001FF4B9 /* MGLFeature_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAD1656A1CF41981001FF4B9 /* MGLFeature_Private.h */; }; + DAD165701CF41981001FF4B9 /* MGLFeature.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAD1656B1CF41981001FF4B9 /* MGLFeature.mm */; }; + DAD165711CF41981001FF4B9 /* MGLFeature.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAD1656B1CF41981001FF4B9 /* MGLFeature.mm */; }; + DAD165781CF4CDFF001FF4B9 /* MGLShapeCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = DAD165761CF4CDFF001FF4B9 /* MGLShapeCollection.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAD165791CF4CDFF001FF4B9 /* MGLShapeCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = DAD165761CF4CDFF001FF4B9 /* MGLShapeCollection.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAD1657A1CF4CDFF001FF4B9 /* MGLShapeCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = DAD165771CF4CDFF001FF4B9 /* MGLShapeCollection.m */; }; + DAD1657B1CF4CDFF001FF4B9 /* MGLShapeCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = DAD165771CF4CDFF001FF4B9 /* MGLShapeCollection.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -474,6 +483,11 @@ DABCABC01CB80717000A7C39 /* locations.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = locations.hpp; sourceTree = "<group>"; }; DAC07C961CBB2CD6000CB309 /* mbgl.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = mbgl.xcconfig; path = ../../build/ios/mbgl.xcconfig; sourceTree = "<group>"; }; DAC49C621CD07D74009E1AA3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; }; + DAD165691CF41981001FF4B9 /* MGLFeature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature.h; sourceTree = "<group>"; }; + DAD1656A1CF41981001FF4B9 /* MGLFeature_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature_Private.h; sourceTree = "<group>"; }; + DAD1656B1CF41981001FF4B9 /* MGLFeature.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFeature.mm; sourceTree = "<group>"; }; + DAD165761CF4CDFF001FF4B9 /* MGLShapeCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeCollection.h; sourceTree = "<group>"; }; + DAD165771CF4CDFF001FF4B9 /* MGLShapeCollection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLShapeCollection.m; sourceTree = "<group>"; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -654,56 +668,19 @@ DA8847DE1CBAFA3E00AB86E3 /* Foundation */ = { isa = PBXGroup; children = ( + DAD165831CF4CFED001FF4B9 /* Categories */, + DAD165801CF4CF9A001FF4B9 /* Formatters */, + DAD165811CF4CFC4001FF4B9 /* Geometry */, + DAD165821CF4CFE3001FF4B9 /* Offline Maps */, DA8847DF1CBAFA5100AB86E3 /* MGLAccountManager.h */, DA8847FF1CBAFA6200AB86E3 /* MGLAccountManager_Private.h */, DA8848001CBAFA6200AB86E3 /* MGLAccountManager.m */, - DA8847E01CBAFA5100AB86E3 /* MGLAnnotation.h */, - DA35A2BA1CCA9A6900E826B2 /* MGLClockDirectionFormatter.h */, - DA35A2B71CCA9A5D00E826B2 /* MGLClockDirectionFormatter.m */, - DA35A2AF1CCA141D00E826B2 /* MGLCompassDirectionFormatter.h */, - DA35A2B01CCA141D00E826B2 /* MGLCompassDirectionFormatter.m */, - DA35A29D1CC9E94C00E826B2 /* MGLCoordinateFormatter.h */, - DA35A2A01CC9E95F00E826B2 /* MGLCoordinateFormatter.m */, - DA8847E11CBAFA5100AB86E3 /* MGLGeometry.h */, - DA8848011CBAFA6200AB86E3 /* MGLGeometry_Private.h */, - DA8848021CBAFA6200AB86E3 /* MGLGeometry.mm */, DA8847E21CBAFA5100AB86E3 /* MGLMapCamera.h */, DA8848031CBAFA6200AB86E3 /* MGLMapCamera.mm */, - DA8847E31CBAFA5100AB86E3 /* MGLMultiPoint.h */, - DA8848041CBAFA6200AB86E3 /* MGLMultiPoint_Private.h */, - DA8848051CBAFA6200AB86E3 /* MGLMultiPoint.mm */, - DA8847E41CBAFA5100AB86E3 /* MGLOfflinePack.h */, - DA8848061CBAFA6200AB86E3 /* MGLOfflinePack_Private.h */, - DA8848071CBAFA6200AB86E3 /* MGLOfflinePack.mm */, - DA8847E51CBAFA5100AB86E3 /* MGLOfflineRegion.h */, - DA8848081CBAFA6200AB86E3 /* MGLOfflineRegion_Private.h */, - DA8847E61CBAFA5100AB86E3 /* MGLOfflineStorage.h */, - DA8848091CBAFA6200AB86E3 /* MGLOfflineStorage_Private.h */, - DA88480A1CBAFA6200AB86E3 /* MGLOfflineStorage.mm */, - DA8847E71CBAFA5100AB86E3 /* MGLOverlay.h */, - DA8847E81CBAFA5100AB86E3 /* MGLPointAnnotation.h */, - DA88480B1CBAFA6200AB86E3 /* MGLPointAnnotation.m */, - DA8847E91CBAFA5100AB86E3 /* MGLPolygon.h */, - DA88480C1CBAFA6200AB86E3 /* MGLPolygon.mm */, - DA8847EA1CBAFA5100AB86E3 /* MGLPolyline.h */, - DA88480D1CBAFA6200AB86E3 /* MGLPolyline.mm */, - DA8847EB1CBAFA5100AB86E3 /* MGLShape.h */, - DA88480E1CBAFA6200AB86E3 /* MGLShape.m */, DA8847EC1CBAFA5100AB86E3 /* MGLStyle.h */, DA88480F1CBAFA6200AB86E3 /* MGLStyle.mm */, - DA8847ED1CBAFA5100AB86E3 /* MGLTilePyramidOfflineRegion.h */, - DA8848101CBAFA6200AB86E3 /* MGLTilePyramidOfflineRegion.mm */, DA8847EE1CBAFA5100AB86E3 /* MGLTypes.h */, DA8848111CBAFA6200AB86E3 /* MGLTypes.m */, - DA8848121CBAFA6200AB86E3 /* NSBundle+MGLAdditions.h */, - DA8848131CBAFA6200AB86E3 /* NSBundle+MGLAdditions.m */, - DA8848141CBAFA6200AB86E3 /* NSException+MGLAdditions.h */, - DA8848151CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.h */, - DA8848161CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.m */, - DA8848171CBAFA6200AB86E3 /* NSString+MGLAdditions.h */, - DA8848181CBAFA6200AB86E3 /* NSString+MGLAdditions.m */, - DA35A2C71CCAAAD200E826B2 /* NSValue+MGLAdditions.h */, - DA35A2C81CCAAAD200E826B2 /* NSValue+MGLAdditions.m */, DA8848911CBB049300AB86E3 /* reachability */, ); name = Foundation; @@ -713,31 +690,13 @@ DA8848331CBAFB2A00AB86E3 /* Kit */ = { isa = PBXGroup; children = ( - 4018B1C31CDC277F00F666AF /* MGLAnnotationView_Private.h */, - 4018B1C41CDC277F00F666AF /* MGLAnnotationView.mm */, - 4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */, - DA8848341CBAFB8500AB86E3 /* MGLAnnotationImage.h */, - DA8848401CBAFB9800AB86E3 /* MGLAnnotationImage_Private.h */, - DA8848411CBAFB9800AB86E3 /* MGLAnnotationImage.m */, - DA8848421CBAFB9800AB86E3 /* MGLAPIClient.h */, - DA8848431CBAFB9800AB86E3 /* MGLAPIClient.m */, - DA8848351CBAFB8500AB86E3 /* MGLCalloutView.h */, - DA8848441CBAFB9800AB86E3 /* MGLCompactCalloutView.h */, - DA8848451CBAFB9800AB86E3 /* MGLCompactCalloutView.m */, - DA8848461CBAFB9800AB86E3 /* MGLLocationManager.h */, - DA8848471CBAFB9800AB86E3 /* MGLLocationManager.m */, - DA8848481CBAFB9800AB86E3 /* MGLMapboxEvents.h */, - DA8848491CBAFB9800AB86E3 /* MGLMapboxEvents.m */, + DAD165841CF4D06B001FF4B9 /* Annotations */, + DAD165851CF4D08B001FF4B9 /* Telemetry */, DA8848361CBAFB8500AB86E3 /* MGLMapView.h */, DA17BE2F1CC4BAC300402C41 /* MGLMapView_Internal.h */, DA8848371CBAFB8500AB86E3 /* MGLMapView+IBAdditions.h */, DA8848381CBAFB8500AB86E3 /* MGLMapView+MGLCustomStyleLayerAdditions.h */, DA88484A1CBAFB9800AB86E3 /* MGLMapView.mm */, - DA8848391CBAFB8500AB86E3 /* MGLUserLocation.h */, - DA88484B1CBAFB9800AB86E3 /* MGLUserLocation_Private.h */, - DA88484C1CBAFB9800AB86E3 /* MGLUserLocation.m */, - DA88484D1CBAFB9800AB86E3 /* MGLUserLocationAnnotationView.h */, - DA88484E1CBAFB9800AB86E3 /* MGLUserLocationAnnotationView.m */, DA88487F1CBB033F00AB86E3 /* Fabric */, DA8848881CBB036000AB86E3 /* SMCalloutView */, ); @@ -858,6 +817,114 @@ name = Configuration; sourceTree = "<group>"; }; + DAD165801CF4CF9A001FF4B9 /* Formatters */ = { + isa = PBXGroup; + children = ( + DA35A2BA1CCA9A6900E826B2 /* MGLClockDirectionFormatter.h */, + DA35A2B71CCA9A5D00E826B2 /* MGLClockDirectionFormatter.m */, + DA35A2AF1CCA141D00E826B2 /* MGLCompassDirectionFormatter.h */, + DA35A2B01CCA141D00E826B2 /* MGLCompassDirectionFormatter.m */, + DA35A29D1CC9E94C00E826B2 /* MGLCoordinateFormatter.h */, + DA35A2A01CC9E95F00E826B2 /* MGLCoordinateFormatter.m */, + ); + name = Formatters; + sourceTree = "<group>"; + }; + DAD165811CF4CFC4001FF4B9 /* Geometry */ = { + isa = PBXGroup; + children = ( + DA8847E01CBAFA5100AB86E3 /* MGLAnnotation.h */, + DAD165691CF41981001FF4B9 /* MGLFeature.h */, + DAD1656A1CF41981001FF4B9 /* MGLFeature_Private.h */, + DAD1656B1CF41981001FF4B9 /* MGLFeature.mm */, + DA8847E11CBAFA5100AB86E3 /* MGLGeometry.h */, + DA8848011CBAFA6200AB86E3 /* MGLGeometry_Private.h */, + DA8848021CBAFA6200AB86E3 /* MGLGeometry.mm */, + DA8847E31CBAFA5100AB86E3 /* MGLMultiPoint.h */, + DA8848041CBAFA6200AB86E3 /* MGLMultiPoint_Private.h */, + DA8848051CBAFA6200AB86E3 /* MGLMultiPoint.mm */, + DA8847E71CBAFA5100AB86E3 /* MGLOverlay.h */, + DA8847E81CBAFA5100AB86E3 /* MGLPointAnnotation.h */, + DA88480B1CBAFA6200AB86E3 /* MGLPointAnnotation.m */, + DA8847E91CBAFA5100AB86E3 /* MGLPolygon.h */, + DA88480C1CBAFA6200AB86E3 /* MGLPolygon.mm */, + DA8847EA1CBAFA5100AB86E3 /* MGLPolyline.h */, + DA88480D1CBAFA6200AB86E3 /* MGLPolyline.mm */, + DA8847EB1CBAFA5100AB86E3 /* MGLShape.h */, + DA88480E1CBAFA6200AB86E3 /* MGLShape.m */, + DAD165761CF4CDFF001FF4B9 /* MGLShapeCollection.h */, + DAD165771CF4CDFF001FF4B9 /* MGLShapeCollection.m */, + ); + name = Geometry; + sourceTree = "<group>"; + }; + DAD165821CF4CFE3001FF4B9 /* Offline Maps */ = { + isa = PBXGroup; + children = ( + DA8847E41CBAFA5100AB86E3 /* MGLOfflinePack.h */, + DA8848061CBAFA6200AB86E3 /* MGLOfflinePack_Private.h */, + DA8848071CBAFA6200AB86E3 /* MGLOfflinePack.mm */, + DA8847E51CBAFA5100AB86E3 /* MGLOfflineRegion.h */, + DA8848081CBAFA6200AB86E3 /* MGLOfflineRegion_Private.h */, + DA8847E61CBAFA5100AB86E3 /* MGLOfflineStorage.h */, + DA8848091CBAFA6200AB86E3 /* MGLOfflineStorage_Private.h */, + DA88480A1CBAFA6200AB86E3 /* MGLOfflineStorage.mm */, + DA8847ED1CBAFA5100AB86E3 /* MGLTilePyramidOfflineRegion.h */, + DA8848101CBAFA6200AB86E3 /* MGLTilePyramidOfflineRegion.mm */, + ); + name = "Offline Maps"; + sourceTree = "<group>"; + }; + DAD165831CF4CFED001FF4B9 /* Categories */ = { + isa = PBXGroup; + children = ( + DA8848121CBAFA6200AB86E3 /* NSBundle+MGLAdditions.h */, + DA8848131CBAFA6200AB86E3 /* NSBundle+MGLAdditions.m */, + DA8848141CBAFA6200AB86E3 /* NSException+MGLAdditions.h */, + DA8848151CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.h */, + DA8848161CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.m */, + DA8848171CBAFA6200AB86E3 /* NSString+MGLAdditions.h */, + DA8848181CBAFA6200AB86E3 /* NSString+MGLAdditions.m */, + DA35A2C71CCAAAD200E826B2 /* NSValue+MGLAdditions.h */, + DA35A2C81CCAAAD200E826B2 /* NSValue+MGLAdditions.m */, + ); + name = Categories; + sourceTree = "<group>"; + }; + DAD165841CF4D06B001FF4B9 /* Annotations */ = { + isa = PBXGroup; + children = ( + 4018B1C31CDC277F00F666AF /* MGLAnnotationView_Private.h */, + 4018B1C41CDC277F00F666AF /* MGLAnnotationView.mm */, + 4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */, + DA8848341CBAFB8500AB86E3 /* MGLAnnotationImage.h */, + DA8848401CBAFB9800AB86E3 /* MGLAnnotationImage_Private.h */, + DA8848411CBAFB9800AB86E3 /* MGLAnnotationImage.m */, + DA8848351CBAFB8500AB86E3 /* MGLCalloutView.h */, + DA8848441CBAFB9800AB86E3 /* MGLCompactCalloutView.h */, + DA8848451CBAFB9800AB86E3 /* MGLCompactCalloutView.m */, + DA8848391CBAFB8500AB86E3 /* MGLUserLocation.h */, + DA88484B1CBAFB9800AB86E3 /* MGLUserLocation_Private.h */, + DA88484C1CBAFB9800AB86E3 /* MGLUserLocation.m */, + DA88484D1CBAFB9800AB86E3 /* MGLUserLocationAnnotationView.h */, + DA88484E1CBAFB9800AB86E3 /* MGLUserLocationAnnotationView.m */, + ); + name = Annotations; + sourceTree = "<group>"; + }; + DAD165851CF4D08B001FF4B9 /* Telemetry */ = { + isa = PBXGroup; + children = ( + DA8848421CBAFB9800AB86E3 /* MGLAPIClient.h */, + DA8848431CBAFB9800AB86E3 /* MGLAPIClient.m */, + DA8848461CBAFB9800AB86E3 /* MGLLocationManager.h */, + DA8848471CBAFB9800AB86E3 /* MGLLocationManager.m */, + DA8848481CBAFB9800AB86E3 /* MGLMapboxEvents.h */, + DA8848491CBAFB9800AB86E3 /* MGLMapboxEvents.m */, + ); + name = Telemetry; + sourceTree = "<group>"; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -894,6 +961,7 @@ DA88483F1CBAFB8500AB86E3 /* MGLUserLocation.h in Headers */, DA88483D1CBAFB8500AB86E3 /* MGLMapView+IBAdditions.h in Headers */, DA17BE301CC4BAC300402C41 /* MGLMapView_Internal.h in Headers */, + DAD165781CF4CDFF001FF4B9 /* MGLShapeCollection.h in Headers */, DA88481E1CBAFA6200AB86E3 /* MGLMultiPoint_Private.h in Headers */, DA35A29E1CC9E94C00E826B2 /* MGLCoordinateFormatter.h in Headers */, DA8847F71CBAFA5100AB86E3 /* MGLOverlay.h in Headers */, @@ -905,6 +973,7 @@ DA8847F91CBAFA5100AB86E3 /* MGLPolygon.h in Headers */, DA8847F81CBAFA5100AB86E3 /* MGLPointAnnotation.h in Headers */, DA8847F31CBAFA5100AB86E3 /* MGLMultiPoint.h in Headers */, + DAD1656C1CF41981001FF4B9 /* MGLFeature.h in Headers */, DA88484F1CBAFB9800AB86E3 /* MGLAnnotationImage_Private.h in Headers */, DA8847F21CBAFA5100AB86E3 /* MGLMapCamera.h in Headers */, DA8847F51CBAFA5100AB86E3 /* MGLOfflineRegion.h in Headers */, @@ -917,6 +986,7 @@ DA88482F1CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.h in Headers */, DA8848601CBAFC2E00AB86E3 /* Mapbox.h in Headers */, DA8847F61CBAFA5100AB86E3 /* MGLOfflineStorage.h in Headers */, + DAD1656E1CF41981001FF4B9 /* MGLFeature_Private.h in Headers */, DA88483C1CBAFB8500AB86E3 /* MGLMapView.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -928,6 +998,7 @@ DA35A2CA1CCAAAD200E826B2 /* NSValue+MGLAdditions.h in Headers */, DABFB85E1CBE99E500D62B32 /* MGLAnnotation.h in Headers */, DABFB8641CBE99E500D62B32 /* MGLOfflineStorage.h in Headers */, + DAD165791CF4CDFF001FF4B9 /* MGLShapeCollection.h in Headers */, DA35A29F1CC9E94C00E826B2 /* MGLCoordinateFormatter.h in Headers */, DABFB8711CBE9A0F00D62B32 /* MGLMapView+MGLCustomStyleLayerAdditions.h in Headers */, DABFB8611CBE99E500D62B32 /* MGLMultiPoint.h in Headers */, @@ -935,6 +1006,7 @@ DABFB8721CBE9A0F00D62B32 /* MGLUserLocation.h in Headers */, DABFB8661CBE99E500D62B32 /* MGLPointAnnotation.h in Headers */, DABFB8621CBE99E500D62B32 /* MGLOfflinePack.h in Headers */, + DAD1656D1CF41981001FF4B9 /* MGLFeature.h in Headers */, DA17BE311CC4BDAA00402C41 /* MGLMapView_Internal.h in Headers */, DABFB86C1CBE99E500D62B32 /* MGLTypes.h in Headers */, DABFB8691CBE99E500D62B32 /* MGLShape.h in Headers */, @@ -1270,12 +1342,14 @@ buildActionMask = 2147483647; files = ( DA88485D1CBAFB9800AB86E3 /* MGLUserLocationAnnotationView.m in Sources */, + DAD165701CF41981001FF4B9 /* MGLFeature.mm in Sources */, DA8848541CBAFB9800AB86E3 /* MGLCompactCalloutView.m in Sources */, DA8848251CBAFA6200AB86E3 /* MGLPointAnnotation.m in Sources */, DA88482D1CBAFA6200AB86E3 /* NSBundle+MGLAdditions.m in Sources */, DA88485B1CBAFB9800AB86E3 /* MGLUserLocation.m in Sources */, DA88488C1CBB037E00AB86E3 /* SMCalloutView.m in Sources */, DA35A2B81CCA9A5D00E826B2 /* MGLClockDirectionFormatter.m in Sources */, + DAD1657A1CF4CDFF001FF4B9 /* MGLShapeCollection.m in Sources */, DA8848901CBB048E00AB86E3 /* reachability.m in Sources */, DA8848211CBAFA6200AB86E3 /* MGLOfflinePack.mm in Sources */, DA8848591CBAFB9800AB86E3 /* MGLMapView.mm in Sources */, @@ -1308,12 +1382,14 @@ buildActionMask = 2147483647; files = ( DAA4E4221CBB730400178DFB /* MGLPointAnnotation.m in Sources */, + DAD165711CF41981001FF4B9 /* MGLFeature.mm in Sources */, DAA4E4291CBB730400178DFB /* NSBundle+MGLAdditions.m in Sources */, DAA4E42E1CBB730400178DFB /* MGLAPIClient.m in Sources */, DAA4E4201CBB730400178DFB /* MGLOfflinePack.mm in Sources */, DAA4E4331CBB730400178DFB /* MGLUserLocation.m in Sources */, DAA4E4351CBB730400178DFB /* SMCalloutView.m in Sources */, DA35A2B91CCA9A5D00E826B2 /* MGLClockDirectionFormatter.m in Sources */, + DAD1657B1CF4CDFF001FF4B9 /* MGLShapeCollection.m in Sources */, DAA4E4251CBB730400178DFB /* MGLShape.m in Sources */, DAA4E42B1CBB730400178DFB /* NSString+MGLAdditions.m in Sources */, DAA4E4261CBB730400178DFB /* MGLStyle.mm in Sources */, diff --git a/platform/ios/jazzy.yml b/platform/ios/jazzy.yml index f6a5cfba4b..61570994d5 100644 --- a/platform/ios/jazzy.yml +++ b/platform/ios/jazzy.yml @@ -33,12 +33,25 @@ custom_categories: - MGLCalloutView - MGLCalloutViewDelegate - MGLMultiPoint + - MGLMultiPolygon + - MGLMultiPolyline - MGLPointAnnotation - MGLPolygon - MGLPolyline - MGLOverlay - MGLShape + - MGLShapeCollection - MGLUserLocation + - name: Map Data + children: + - MGLFeature + - MGLMultiPointFeature + - MGLMultiPolygonFeature + - MGLMultiPolylineFeature + - MGLPointFeature + - MGLPolygonFeature + - MGLPolylineFeature + - MGLShapeCollectionFeature - name: Offline Maps children: - MGLOfflineRegion diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h index 3f54b07f41..725677a65b 100644 --- a/platform/ios/src/MGLMapView.h +++ b/platform/ios/src/MGLMapView.h @@ -19,6 +19,7 @@ NS_ASSUME_NONNULL_BEGIN @protocol MGLAnnotation; @protocol MGLOverlay; @protocol MGLCalloutView; +@protocol MGLFeature; /** The vertical alignment of an annotation within a map view. */ typedef NS_ENUM(NSUInteger, MGLAnnotationVerticalAlignment) { @@ -1021,6 +1022,132 @@ IB_DESIGNABLE */ - (void)removeOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays; +#pragma mark Accessing the Underlying Map Data + +/** + Returns an array of rendered map features that intersect with a given point. + + This method may return features from any of the map’s style layers. To restrict + the search to a particular layer or layers, use the + `-visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:` method. For more + information about searching for map features, see that method’s documentation. + + @param point A point expressed in the map view’s coordinate system. + @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>) *)visibleFeaturesAtPoint:(CGPoint)point NS_SWIFT_NAME(visibleFeatures(at:)); + +/** + Returns an array of rendered map features that intersect with a given point, + restricted to the given style layers. + + Each object in the returned array represents a feature rendered by the + 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. + + Only visible features are returned. For example, suppose the current style uses + the + <a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets source</a>, + but none of the specified style layers includes features that have the `maki` + property set to `bus`. If you pass a point corresponding to the location of a + bus stop into this method, the bus stop feature does not appear in the + resulting array. On the other hand, if the style does include bus stops, an + `MGLFeature` object representing that bus stop is returned and its + `featureAttributes` dictionary has the `maki` key set to `bus` (along with + other attributes). The dictionary contains only the attributes provided by the + tile source; it does not include computed attribute values or rules about how + the feature is rendered by the current style. + + The returned array is sorted by z-order, starting with the topmost rendered + feature and ending with the bottommost rendered feature. A feature that is + rendered multiple times due to wrapping across the antimeridian at low zoom + levels is included only once, subject to the caveat that follows. + + 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 point + lies along a road that spans the screen. The resulting array includes those + parts of the road that lie within the map tile that contain the specified + point, even if the road extends into other tiles. + + To find out the layer names in a particular style, view the style in + <a href="https://www.mapbox.com/studio/">Mapbox Studio</a>. + + @param point A point expressed in the map view’s coordinate system. + @param styleLayerIdentifiers A set of strings that correspond to the names of + layers defined in the current style. Only the features contained in these + layers are included in the returned array. + @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>) *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:)); + +/** + Returns an array of rendered map features that intersect with the given + rectangle. + + This method may return features from any of the map’s style layers. To restrict + the search to a particular layer or layers, use the + `-visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:` method. For more + information about searching for map features, see that method’s documentation. + + @param rect A rectangle expressed in the map view’s coordinate system. + @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>) *)visibleFeaturesInRect:(CGRect)rect NS_SWIFT_NAME(visibleFeatures(in:)); + +/** + Returns an array of rendered map features that intersect with the given + rectangle, restricted to the given style layers. + + Each object in the returned array represents a feature rendered by the + 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. + + Only visible features are returned. For example, suppose the current style uses + the + <a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets source</a>, + but none of the specified style layers includes features that have the `maki` + property set to `bus`. If you pass a rectangle containing the location of a bus + stop into this method, the bus stop feature does not appear in the resulting + array. On the other hand, if the style does include bus stops, an `MGLFeature` + object representing that bus stop is returned and its `featureAttributes` + dictionary has the `maki` key set to `bus` (along with other attributes). The + dictionary contains only the attributes provided by the tile source; it does + not include computed attribute values or rules about how the feature is + rendered by the current style. + + The returned array is sorted by z-order, starting with the topmost rendered + feature and ending with the bottommost rendered feature. A feature that is + rendered multiple times due to wrapping across the antimeridian at low zoom + levels is included only once, subject to the caveat that follows. + + 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 + includes those parts of the road that lie within the map tiles covering the + specified rectangle, even if the road extends into other tiles. The portion of + the road within each map tile is included individually. + + To find out the layer names in a particular style, view the style in + <a href="https://www.mapbox.com/studio/">Mapbox Studio</a>. + + @param rect A rectangle expressed in the map view’s coordinate system. + @param styleLayerIdentifiers A set of strings that correspond to the names of + layers defined in the current style. Only the features contained in these + layers are included in the returned array. + @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>) *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(in:styleLayerIdentifiers:)); + #pragma mark Debugging the Map /** diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index b9acdfb1d5..44a3cbc4c8 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -26,6 +26,7 @@ #include <mbgl/util/chrono.hpp> #import "Mapbox.h" +#import "MGLFeature_Private.h" #import "MGLGeometry_Private.h" #import "MGLMultiPoint_Private.h" #import "MGLOfflineStorage_Private.h" @@ -2814,6 +2815,22 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) [(MGLMultiPoint *)annotation addShapeAnnotationObjectToCollection:shapes withDelegate:self]; [userShapes addObject:annotation]; } + else if ([annotation isKindOfClass:[MGLMultiPolyline class]]) + { + // TODO: Add real support for these types down in mbgl instead of breaking the annotation apart. + NS_ARRAY_OF(MGLPolyline *) *polylines = [(MGLMultiPolyline *)annotation polylines]; + [self addAnnotations:polylines]; + } + else if ([annotation isKindOfClass:[MGLMultiPolygon class]]) + { + NS_ARRAY_OF(MGLPolygon *) *polygons = [(MGLMultiPolygon *)annotation polygons]; + [self addAnnotations:polygons]; + } + else if ([annotation isKindOfClass:[MGLShapeCollection class]]) + { + NS_ARRAY_OF(MGLShape <MGLAnnotation> *) *shapes = [(MGLShapeCollection *)annotation shapes]; + [self addAnnotations:shapes]; + } else { MGLAnnotationView *annotationView; @@ -4184,6 +4201,57 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) } } +#pragma mark Data + +- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point +{ + return [self visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:nil]; +} + +- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers +{ + mbgl::ScreenCoordinate screenCoordinate = { point.x, point.y }; + + mbgl::optional<std::vector<std::string>> optionalLayerIDs; + if (styleLayerIdentifiers) + { + __block std::vector<std::string> layerIDs; + layerIDs.reserve(styleLayerIdentifiers.count); + [styleLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop) + { + layerIDs.push_back(identifier.UTF8String); + }]; + optionalLayerIDs = layerIDs; + } + + std::vector<mbgl::Feature> features = _mbglMap->queryRenderedFeatures(screenCoordinate, optionalLayerIDs); + return MGLFeaturesFromMBGLFeatures(features); +} + +- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect { + return [self visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:nil]; +} + +- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers { + mbgl::ScreenBox screenBox = { + { CGRectGetMinX(rect), CGRectGetMinY(rect) }, + { CGRectGetMaxX(rect), CGRectGetMaxY(rect) }, + }; + + mbgl::optional<std::vector<std::string>> optionalLayerIDs; + if (styleLayerIdentifiers) { + __block std::vector<std::string> layerIDs; + layerIDs.reserve(styleLayerIdentifiers.count); + [styleLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop) { + layerIDs.push_back(identifier.UTF8String); + }]; + optionalLayerIDs = layerIDs; + } + + std::vector<mbgl::Feature> features = _mbglMap->queryRenderedFeatures(screenBox, optionalLayerIDs); + return MGLFeaturesFromMBGLFeatures(features); +} + #pragma mark - Utility - - (void)animateWithDelay:(NSTimeInterval)delay animations:(void (^)(void))animations diff --git a/platform/ios/src/Mapbox.h b/platform/ios/src/Mapbox.h index 3b7361a756..013bb81614 100644 --- a/platform/ios/src/Mapbox.h +++ b/platform/ios/src/Mapbox.h @@ -14,8 +14,9 @@ FOUNDATION_EXPORT const unsigned char MapboxVersionString[]; #import "MGLClockDirectionFormatter.h" #import "MGLCompassDirectionFormatter.h" #import "MGLCoordinateFormatter.h" -#import "MGLMapCamera.h" +#import "MGLFeature.h" #import "MGLGeometry.h" +#import "MGLMapCamera.h" #import "MGLMapView.h" #import "MGLMapView+IBAdditions.h" #import "MGLMapView+MGLCustomStyleLayerAdditions.h" @@ -28,6 +29,7 @@ FOUNDATION_EXPORT const unsigned char MapboxVersionString[]; #import "MGLPolygon.h" #import "MGLPolyline.h" #import "MGLShape.h" +#import "MGLShapeCollection.h" #import "MGLStyle.h" #import "MGLTilePyramidOfflineRegion.h" #import "MGLTypes.h" diff --git a/platform/osx/CHANGELOG.md b/platform/osx/CHANGELOG.md index 67bdce1e6c..0e4da04545 100644 --- a/platform/osx/CHANGELOG.md +++ b/platform/osx/CHANGELOG.md @@ -3,6 +3,7 @@ ## master * Fixed an issue in which Mapbox.framework was nested inside another folder named Mapbox.framework. ([#4998](https://github.com/mapbox/mapbox-gl-native/pull/4998)) +* Added methods to MGLMapView for obtaining the underlying map data rendered by the current style. ([#5110](https://github.com/mapbox/mapbox-gl-native/pull/5110)) * Fixed a crash passing a mixture of point and shape annotations into `-[MGLMapView addAnnotations:]`. ([#5097](https://github.com/mapbox/mapbox-gl-native/pull/5097)) * Added new options to `MGLMapDebugMaskOptions` that show wireframes and the stencil buffer instead of the color buffer. ([#4359](https://github.com/mapbox/mapbox-gl-native/pull/4359)) * Fixed a memory leak when using raster resources. ([#5141](https://github.com/mapbox/mapbox-gl-native/pull/5141)) diff --git a/platform/osx/app/MapDocument.m b/platform/osx/app/MapDocument.m index 9bff4603e4..6fcfc7ce5d 100644 --- a/platform/osx/app/MapDocument.m +++ b/platform/osx/app/MapDocument.m @@ -420,7 +420,8 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = { if (!NSPointInRect([gestureRecognizer locationInView:self.mapView.compass], self.mapView.compass.bounds) && !NSPointInRect([gestureRecognizer locationInView:self.mapView.zoomControls], self.mapView.zoomControls.bounds) && !NSPointInRect([gestureRecognizer locationInView:self.mapView.attributionView], self.mapView.attributionView.bounds)) { - [self dropPinAtPoint:location]; + NSArray *features = [self.mapView visibleFeaturesAtPoint:location]; + [self.mapView addAnnotations:features]; } } } @@ -436,9 +437,17 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = { } - (DroppedPinAnnotation *)pinAtPoint:(NSPoint)point { + NSArray *features = [self.mapView visibleFeaturesAtPoint:point]; + NSString *title; + for (id <MGLFeature> feature in features) { + if (!title) { + title = [feature attributeForKey:@"name_en"] ?: [feature attributeForKey:@"name"]; + } + } + DroppedPinAnnotation *annotation = [[DroppedPinAnnotation alloc] init]; annotation.coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView]; - annotation.title = @"Dropped Pin"; + annotation.title = title ?: @"Dropped Pin"; _spellOutNumberFormatter.numberStyle = NSNumberFormatterSpellOutStyle; if (_showsToolTipsOnDroppedPins) { NSString *formattedNumber = [_spellOutNumberFormatter stringFromNumber:@(++_droppedPinCounter)]; @@ -706,6 +715,10 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = { } } +- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation { + return 0.8; +} + @end @interface ValidatedToolbarItem : NSToolbarItem diff --git a/platform/osx/jazzy.yml b/platform/osx/jazzy.yml index b1aca9bb45..9e160d050f 100644 --- a/platform/osx/jazzy.yml +++ b/platform/osx/jazzy.yml @@ -29,11 +29,24 @@ custom_categories: - MGLAnnotation - MGLAnnotationImage - MGLMultiPoint + - MGLMultiPolygon + - MGLMultiPolyline - MGLPointAnnotation - MGLPolygon - MGLPolyline - MGLOverlay - MGLShape + - MGLShapeCollection + - name: Map Data + children: + - MGLFeature + - MGLMultiPointFeature + - MGLMultiPolygonFeature + - MGLMultiPolylineFeature + - MGLPointFeature + - MGLPolygonFeature + - MGLPolylineFeature + - MGLShapeCollectionFeature - name: Offline Maps children: - MGLOfflineRegion diff --git a/platform/osx/osx.xcodeproj/project.pbxproj b/platform/osx/osx.xcodeproj/project.pbxproj index 270b2e33d2..762cd39fa1 100644 --- a/platform/osx/osx.xcodeproj/project.pbxproj +++ b/platform/osx/osx.xcodeproj/project.pbxproj @@ -31,6 +31,11 @@ DA8933B81CCD2C2D00E68420 /* Foundation.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DA8933B61CCD2C2D00E68420 /* Foundation.stringsdict */; }; DAB6924A1CC75A31005AAB54 /* libmbgl-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */; }; DAC2ABC51CC6D343006D18C4 /* MGLAnnotationImage_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC2ABC41CC6D343006D18C4 /* MGLAnnotationImage_Private.h */; }; + DACC22141CF3D3E200D220D9 /* MGLFeature.h in Headers */ = {isa = PBXBuildFile; fileRef = DACC22121CF3D3E200D220D9 /* MGLFeature.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DACC22151CF3D3E200D220D9 /* MGLFeature.mm in Sources */ = {isa = PBXBuildFile; fileRef = DACC22131CF3D3E200D220D9 /* MGLFeature.mm */; }; + DACC22181CF3D4F700D220D9 /* MGLFeature_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DACC22171CF3D4F700D220D9 /* MGLFeature_Private.h */; }; + DAD165741CF4CD7A001FF4B9 /* MGLShapeCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = DAD165721CF4CD7A001FF4B9 /* MGLShapeCollection.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DAD165751CF4CD7A001FF4B9 /* MGLShapeCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = DAD165731CF4CD7A001FF4B9 /* MGLShapeCollection.m */; }; DAE6C2E21CC304F900DB3429 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = DAE6C2E11CC304F900DB3429 /* Credits.rtf */; }; DAE6C2ED1CC3050F00DB3429 /* DroppedPinAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C2E41CC3050F00DB3429 /* DroppedPinAnnotation.m */; }; DAE6C2EE1CC3050F00DB3429 /* LocationCoordinate2DTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C2E61CC3050F00DB3429 /* LocationCoordinate2DTransformer.m */; }; @@ -167,6 +172,11 @@ DA8933B41CCD2C2500E68420 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Foundation.strings; sourceTree = "<group>"; }; DA8933B71CCD2C2D00E68420 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Foundation.stringsdict; sourceTree = "<group>"; }; DAC2ABC41CC6D343006D18C4 /* MGLAnnotationImage_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationImage_Private.h; sourceTree = "<group>"; }; + DACC22121CF3D3E200D220D9 /* MGLFeature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature.h; sourceTree = "<group>"; }; + DACC22131CF3D3E200D220D9 /* MGLFeature.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFeature.mm; sourceTree = "<group>"; }; + DACC22171CF3D4F700D220D9 /* MGLFeature_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature_Private.h; sourceTree = "<group>"; }; + DAD165721CF4CD7A001FF4B9 /* MGLShapeCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeCollection.h; sourceTree = "<group>"; }; + DAD165731CF4CD7A001FF4B9 /* MGLShapeCollection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLShapeCollection.m; sourceTree = "<group>"; }; DAE6C2E11CC304F900DB3429 /* Credits.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = "<group>"; }; DAE6C2E31CC3050F00DB3429 /* DroppedPinAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DroppedPinAnnotation.h; sourceTree = "<group>"; }; DAE6C2E41CC3050F00DB3429 /* DroppedPinAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DroppedPinAnnotation.m; sourceTree = "<group>"; }; @@ -359,6 +369,80 @@ path = ../../darwin/resources; sourceTree = "<group>"; }; + DAD1657C1CF4CE6B001FF4B9 /* Formatters */ = { + isa = PBXGroup; + children = ( + DA35A2BD1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.h */, + DA35A2BE1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.m */, + DA35A2AB1CCA091800E826B2 /* MGLCompassDirectionFormatter.h */, + DA35A2AC1CCA091800E826B2 /* MGLCompassDirectionFormatter.m */, + DA35A2A31CC9EB1A00E826B2 /* MGLCoordinateFormatter.h */, + DA35A2A51CC9EB2700E826B2 /* MGLCoordinateFormatter.m */, + ); + name = Formatters; + sourceTree = "<group>"; + }; + DAD1657D1CF4CECB001FF4B9 /* Geometry */ = { + isa = PBXGroup; + children = ( + DAE6C34B1CC31E0400DB3429 /* MGLAnnotation.h */, + DACC22121CF3D3E200D220D9 /* MGLFeature.h */, + DACC22171CF3D4F700D220D9 /* MGLFeature_Private.h */, + DACC22131CF3D3E200D220D9 /* MGLFeature.mm */, + DAE6C34C1CC31E0400DB3429 /* MGLGeometry.h */, + DAE6C36C1CC31E2A00DB3429 /* MGLGeometry_Private.h */, + DAE6C36D1CC31E2A00DB3429 /* MGLGeometry.mm */, + DAE6C34E1CC31E0400DB3429 /* MGLMultiPoint.h */, + DAE6C36F1CC31E2A00DB3429 /* MGLMultiPoint_Private.h */, + DAE6C3701CC31E2A00DB3429 /* MGLMultiPoint.mm */, + DAE6C3521CC31E0400DB3429 /* MGLOverlay.h */, + DAE6C3531CC31E0400DB3429 /* MGLPointAnnotation.h */, + DAE6C3761CC31E2A00DB3429 /* MGLPointAnnotation.m */, + DAE6C3541CC31E0400DB3429 /* MGLPolygon.h */, + DAE6C3771CC31E2A00DB3429 /* MGLPolygon.mm */, + DAE6C3551CC31E0400DB3429 /* MGLPolyline.h */, + DAE6C3781CC31E2A00DB3429 /* MGLPolyline.mm */, + DAE6C3561CC31E0400DB3429 /* MGLShape.h */, + DAE6C3791CC31E2A00DB3429 /* MGLShape.m */, + DAD165721CF4CD7A001FF4B9 /* MGLShapeCollection.h */, + DAD165731CF4CD7A001FF4B9 /* MGLShapeCollection.m */, + ); + name = Geometry; + sourceTree = "<group>"; + }; + DAD1657E1CF4CF04001FF4B9 /* Offline Maps */ = { + isa = PBXGroup; + children = ( + DAE6C34F1CC31E0400DB3429 /* MGLOfflinePack.h */, + DAE6C3711CC31E2A00DB3429 /* MGLOfflinePack_Private.h */, + DAE6C3721CC31E2A00DB3429 /* MGLOfflinePack.mm */, + DAE6C3501CC31E0400DB3429 /* MGLOfflineRegion.h */, + DAE6C3731CC31E2A00DB3429 /* MGLOfflineRegion_Private.h */, + DAE6C3511CC31E0400DB3429 /* MGLOfflineStorage.h */, + DAE6C3741CC31E2A00DB3429 /* MGLOfflineStorage_Private.h */, + DAE6C3751CC31E2A00DB3429 /* MGLOfflineStorage.mm */, + DAE6C3581CC31E0400DB3429 /* MGLTilePyramidOfflineRegion.h */, + DAE6C37B1CC31E2A00DB3429 /* MGLTilePyramidOfflineRegion.mm */, + ); + name = "Offline Maps"; + sourceTree = "<group>"; + }; + DAD1657F1CF4CF50001FF4B9 /* Categories */ = { + isa = PBXGroup; + children = ( + DAE6C37D1CC31E2A00DB3429 /* NSBundle+MGLAdditions.h */, + DAE6C37E1CC31E2A00DB3429 /* NSBundle+MGLAdditions.m */, + DAE6C37F1CC31E2A00DB3429 /* NSException+MGLAdditions.h */, + DAE6C3801CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.h */, + DAE6C3811CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.m */, + DAE6C3821CC31E2A00DB3429 /* NSString+MGLAdditions.h */, + DAE6C3831CC31E2A00DB3429 /* NSString+MGLAdditions.m */, + DA35A2CD1CCAAED300E826B2 /* NSValue+MGLAdditions.h */, + DA35A2CE1CCAAED300E826B2 /* NSValue+MGLAdditions.m */, + ); + name = Categories; + sourceTree = "<group>"; + }; DAE6C31E1CC308BC00DB3429 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -404,56 +488,19 @@ DAE6C3491CC31DF500DB3429 /* Foundation */ = { isa = PBXGroup; children = ( + DAD1657F1CF4CF50001FF4B9 /* Categories */, + DAD1657C1CF4CE6B001FF4B9 /* Formatters */, + DAD1657D1CF4CECB001FF4B9 /* Geometry */, + DAD1657E1CF4CF04001FF4B9 /* Offline Maps */, DAE6C34A1CC31E0400DB3429 /* MGLAccountManager.h */, DAE6C36A1CC31E2A00DB3429 /* MGLAccountManager_Private.h */, DAE6C36B1CC31E2A00DB3429 /* MGLAccountManager.m */, - DAE6C34B1CC31E0400DB3429 /* MGLAnnotation.h */, - DA35A2BD1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.h */, - DA35A2BE1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.m */, - DA35A2AB1CCA091800E826B2 /* MGLCompassDirectionFormatter.h */, - DA35A2AC1CCA091800E826B2 /* MGLCompassDirectionFormatter.m */, - DA35A2A31CC9EB1A00E826B2 /* MGLCoordinateFormatter.h */, - DA35A2A51CC9EB2700E826B2 /* MGLCoordinateFormatter.m */, - DAE6C34C1CC31E0400DB3429 /* MGLGeometry.h */, - DAE6C36C1CC31E2A00DB3429 /* MGLGeometry_Private.h */, - DAE6C36D1CC31E2A00DB3429 /* MGLGeometry.mm */, DAE6C34D1CC31E0400DB3429 /* MGLMapCamera.h */, DAE6C36E1CC31E2A00DB3429 /* MGLMapCamera.mm */, - DAE6C34E1CC31E0400DB3429 /* MGLMultiPoint.h */, - DAE6C36F1CC31E2A00DB3429 /* MGLMultiPoint_Private.h */, - DAE6C3701CC31E2A00DB3429 /* MGLMultiPoint.mm */, - DAE6C34F1CC31E0400DB3429 /* MGLOfflinePack.h */, - DAE6C3711CC31E2A00DB3429 /* MGLOfflinePack_Private.h */, - DAE6C3721CC31E2A00DB3429 /* MGLOfflinePack.mm */, - DAE6C3501CC31E0400DB3429 /* MGLOfflineRegion.h */, - DAE6C3731CC31E2A00DB3429 /* MGLOfflineRegion_Private.h */, - DAE6C3511CC31E0400DB3429 /* MGLOfflineStorage.h */, - DAE6C3741CC31E2A00DB3429 /* MGLOfflineStorage_Private.h */, - DAE6C3751CC31E2A00DB3429 /* MGLOfflineStorage.mm */, - DAE6C3521CC31E0400DB3429 /* MGLOverlay.h */, - DAE6C3531CC31E0400DB3429 /* MGLPointAnnotation.h */, - DAE6C3761CC31E2A00DB3429 /* MGLPointAnnotation.m */, - DAE6C3541CC31E0400DB3429 /* MGLPolygon.h */, - DAE6C3771CC31E2A00DB3429 /* MGLPolygon.mm */, - DAE6C3551CC31E0400DB3429 /* MGLPolyline.h */, - DAE6C3781CC31E2A00DB3429 /* MGLPolyline.mm */, - DAE6C3561CC31E0400DB3429 /* MGLShape.h */, - DAE6C3791CC31E2A00DB3429 /* MGLShape.m */, DAE6C3571CC31E0400DB3429 /* MGLStyle.h */, DAE6C37A1CC31E2A00DB3429 /* MGLStyle.mm */, - DAE6C3581CC31E0400DB3429 /* MGLTilePyramidOfflineRegion.h */, - DAE6C37B1CC31E2A00DB3429 /* MGLTilePyramidOfflineRegion.mm */, DAE6C3591CC31E0400DB3429 /* MGLTypes.h */, DAE6C37C1CC31E2A00DB3429 /* MGLTypes.m */, - DAE6C37D1CC31E2A00DB3429 /* NSBundle+MGLAdditions.h */, - DAE6C37E1CC31E2A00DB3429 /* NSBundle+MGLAdditions.m */, - DAE6C37F1CC31E2A00DB3429 /* NSException+MGLAdditions.h */, - DAE6C3801CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.h */, - DAE6C3811CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.m */, - DAE6C3821CC31E2A00DB3429 /* NSString+MGLAdditions.h */, - DAE6C3831CC31E2A00DB3429 /* NSString+MGLAdditions.m */, - DA35A2CD1CCAAED300E826B2 /* NSValue+MGLAdditions.h */, - DA35A2CE1CCAAED300E826B2 /* NSValue+MGLAdditions.m */, ); name = Foundation; path = ../darwin/src; @@ -506,6 +553,7 @@ DAE6C3611CC31E0400DB3429 /* MGLOfflineStorage.h in Headers */, DAE6C35E1CC31E0400DB3429 /* MGLMultiPoint.h in Headers */, DAE6C3971CC31E2A00DB3429 /* NSBundle+MGLAdditions.h in Headers */, + DAD165741CF4CD7A001FF4B9 /* MGLShapeCollection.h in Headers */, DAE6C3631CC31E0400DB3429 /* MGLPointAnnotation.h in Headers */, DAC2ABC51CC6D343006D18C4 /* MGLAnnotationImage_Private.h in Headers */, DAE6C35F1CC31E0400DB3429 /* MGLOfflinePack.h in Headers */, @@ -528,6 +576,7 @@ DA35A2CF1CCAAED300E826B2 /* NSValue+MGLAdditions.h in Headers */, DAE6C3A61CC31E9400DB3429 /* MGLMapViewDelegate.h in Headers */, DAE6C38B1CC31E2A00DB3429 /* MGLOfflinePack_Private.h in Headers */, + DACC22141CF3D3E200D220D9 /* MGLFeature.h in Headers */, DAE6C35C1CC31E0400DB3429 /* MGLGeometry.h in Headers */, DAE6C35A1CC31E0400DB3429 /* MGLAccountManager.h in Headers */, DAE6C35D1CC31E0400DB3429 /* MGLMapCamera.h in Headers */, @@ -536,6 +585,7 @@ DAE6C3891CC31E2A00DB3429 /* MGLMultiPoint_Private.h in Headers */, DAE6C3A51CC31E9400DB3429 /* MGLMapView+IBAdditions.h in Headers */, DA35A2AD1CCA091800E826B2 /* MGLCompassDirectionFormatter.h in Headers */, + DACC22181CF3D4F700D220D9 /* MGLFeature_Private.h in Headers */, DAE6C3671CC31E0400DB3429 /* MGLStyle.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -718,6 +768,7 @@ DAE6C3B71CC31EF300DB3429 /* MGLMapView.mm in Sources */, DAE6C38C1CC31E2A00DB3429 /* MGLOfflinePack.mm in Sources */, DAE6C3B11CC31EF300DB3429 /* MGLAnnotationImage.m in Sources */, + DACC22151CF3D3E200D220D9 /* MGLFeature.mm in Sources */, DAE6C3B31CC31EF300DB3429 /* MGLAttributionButton.m in Sources */, DAE6C3931CC31E2A00DB3429 /* MGLShape.m in Sources */, DAE6C39D1CC31E2A00DB3429 /* NSString+MGLAdditions.m in Sources */, @@ -738,6 +789,7 @@ DAE6C3851CC31E2A00DB3429 /* MGLAccountManager.m in Sources */, DAE6C3921CC31E2A00DB3429 /* MGLPolyline.mm in Sources */, DAE6C3B51CC31EF300DB3429 /* MGLCompassCell.m in Sources */, + DAD165751CF4CD7A001FF4B9 /* MGLShapeCollection.m in Sources */, DA35A2AE1CCA091800E826B2 /* MGLCompassDirectionFormatter.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1094,6 +1146,7 @@ DAAA17981CE13BAE00731EFE /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; DAE6C3431CC30DB200DB3429 /* Build configuration list for PBXNativeTarget "dynamic" */ = { isa = XCConfigurationList; diff --git a/platform/osx/src/MGLMapView.h b/platform/osx/src/MGLMapView.h index 749b3561d2..c08a257bea 100644 --- a/platform/osx/src/MGLMapView.h +++ b/platform/osx/src/MGLMapView.h @@ -35,6 +35,7 @@ typedef NS_OPTIONS(NSUInteger, MGLMapDebugMaskOptions) { @protocol MGLAnnotation; @protocol MGLMapViewDelegate; @protocol MGLOverlay; +@protocol MGLFeature; /** An interactive, customizable map view with an interface similar to the one @@ -687,6 +688,132 @@ IB_DESIGNABLE */ - (void)removeOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays; +#pragma mark Accessing the Underlying Map Data + +/** + Returns an array of rendered map features that intersect with a given point. + + This method may return features from any of the map’s style layers. To restrict + the search to a particular layer or layers, use the + `-visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:` method. For more + information about searching for map features, see that method’s documentation. + + @param point A point expressed in the map view’s coordinate system. + @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>) *)visibleFeaturesAtPoint:(NSPoint)point NS_SWIFT_NAME(visibleFeatures(_:)); + +/** + Returns an array of rendered map features that intersect with a given point, + restricted to the given style layers. + + Each object in the returned array represents a feature rendered by the + 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. + + Only visible features are returned. For example, suppose the current style uses + the + <a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets source</a>, + but none of the specified style layers includes features that have the `maki` + property set to `bus`. If you pass a point corresponding to the location of a + bus stop into this method, the bus stop feature does not appear in the + resulting array. On the other hand, if the style does include bus stops, an + `MGLFeature` object representing that bus stop is returned and its + `attributes` dictionary has the `maki` key set to `bus` (along with other + attributes). The dictionary contains only the attributes provided by the + tile source; it does not include computed attribute values or rules about how + the feature is rendered by the current style. + + The returned array is sorted by z-order, starting with the topmost rendered + feature and ending with the bottommost rendered feature. A feature that is + rendered multiple times due to wrapping across the antimeridian at low zoom + levels is included only once, subject to the caveat that follows. + + 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 point + lies along a road that spans the screen. The resulting array includes those + parts of the road that lie within the map tile that contain the specified + point, even if the road extends into other tiles. + + To find out the layer names in a particular style, view the style in + <a href="https://www.mapbox.com/studio/">Mapbox Studio</a>. + + @param point A point expressed in the map view’s coordinate system. + @param styleLayerIdentifiers A set of strings that correspond to the names of + layers defined in the current style. Only the features contained in these + layers are included in the returned array. + @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>) *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(_:styleLayerIdentifiers:)); + +/** + Returns an array of rendered map features that intersect with the given + rectangle. + + This method may return features from any of the map’s style layers. To restrict + the search to a particular layer or layers, use the + `-visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:` method. For more + information about searching for map features, see that method’s documentation. + + @param rect A rectangle expressed in the map view’s coordinate system. + @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>) *)visibleFeaturesInRect:(NSRect)rect NS_SWIFT_NAME(visibleFeatures(_:)); + +/** + Returns an array of rendered map features that intersect with the given + rectangle, restricted to the given style layers. + + Each object in the returned array represents a feature rendered by the + 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. + + Only visible features are returned. For example, suppose the current style uses + the + <a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets source</a>, + but none of the specified style layers includes features that have the `maki` + property set to `bus`. If you pass a rectangle containing the location of a bus + stop into this method, the bus stop feature does not appear in the resulting + array. On the other hand, if the style does include bus stops, an `MGLFeature` + object representing that bus stop is returned and its `attributes` dictionary + has the `maki` key set to `bus` (along with other attributes). The dictionary + contains only the attributes provided by the tile source; it does not include + computed attribute values or rules about how the feature is rendered by the + current style. + + The returned array is sorted by z-order, starting with the topmost rendered + feature and ending with the bottommost rendered feature. A feature that is + rendered multiple times due to wrapping across the antimeridian at low zoom + levels is included only once, subject to the caveat that follows. + + 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 + includes those parts of the road that lie within the map tiles covering the + specified rectangle, even if the road extends into other tiles. The portion of + the road within each map tile is included individually. + + To find out the layer names in a particular style, view the style in + <a href="https://www.mapbox.com/studio/">Mapbox Studio</a>. + + @param rect A rectangle expressed in the map view’s coordinate system. + @param styleLayerIdentifiers A set of strings that correspond to the names of + layers defined in the current style. Only the features contained in these + layers are included in the returned array. + @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>) *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(_:styleLayerIdentifiers:)); + #pragma mark Converting Geographic Coordinates /** diff --git a/platform/osx/src/MGLMapView.mm b/platform/osx/src/MGLMapView.mm index 5b85ff7ec2..20e59505b4 100644 --- a/platform/osx/src/MGLMapView.mm +++ b/platform/osx/src/MGLMapView.mm @@ -5,6 +5,7 @@ #import "MGLOpenGLLayer.h" #import "MGLStyle.h" +#import "MGLFeature_Private.h" #import "MGLGeometry_Private.h" #import "MGLMultiPoint_Private.h" #import "MGLOfflineStorage_Private.h" @@ -1616,6 +1617,16 @@ public: // The multipoint knows how to style itself (with the map view’s help). [(MGLMultiPoint *)annotation addShapeAnnotationObjectToCollection:shapes withDelegate:self]; [userShapes addObject:annotation]; + } else if ([annotation isKindOfClass:[MGLMultiPolyline class]]) { + // TODO: Add real support for these types down in mbgl instead of breaking the annotation apart. + NS_ARRAY_OF(MGLPolyline *) *polylines = [(MGLMultiPolyline *)annotation polylines]; + [self addAnnotations:polylines]; + } else if ([annotation isKindOfClass:[MGLMultiPolygon class]]) { + NS_ARRAY_OF(MGLPolygon *) *polygons = [(MGLMultiPolygon *)annotation polygons]; + [self addAnnotations:polygons]; + } else if ([annotation isKindOfClass:[MGLShapeCollection class]]) { + NS_ARRAY_OF(MGLShape <MGLAnnotation> *) *shapes = [(MGLShapeCollection *)annotation shapes]; + [self addAnnotations:shapes]; } else { MGLAnnotationImage *annotationImage = nil; if (delegateHasImagesForAnnotations) { @@ -2246,6 +2257,55 @@ public: } } +#pragma mark Data + +- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(NSPoint)point { + return [self visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:nil]; +} + +- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers { + // Cocoa origin is at the lower-left corner. + mbgl::ScreenCoordinate screenCoordinate = { point.x, NSHeight(self.bounds) - point.y }; + + mbgl::optional<std::vector<std::string>> optionalLayerIDs; + if (styleLayerIdentifiers) { + __block std::vector<std::string> layerIDs; + layerIDs.reserve(styleLayerIdentifiers.count); + [styleLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop) { + layerIDs.push_back(identifier.UTF8String); + }]; + optionalLayerIDs = layerIDs; + } + + std::vector<mbgl::Feature> features = _mbglMap->queryRenderedFeatures(screenCoordinate, optionalLayerIDs); + return MGLFeaturesFromMBGLFeatures(features); +} + +- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(NSRect)rect { + return [self visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:nil]; +} + +- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers { + // Cocoa origin is at the lower-left corner. + mbgl::ScreenBox screenBox = { + { NSMinX(rect), NSHeight(self.bounds) - NSMaxY(rect) }, + { NSMaxX(rect), NSHeight(self.bounds) - NSMinY(rect) }, + }; + + mbgl::optional<std::vector<std::string>> optionalLayerIDs; + if (styleLayerIdentifiers) { + __block std::vector<std::string> layerIDs; + layerIDs.reserve(styleLayerIdentifiers.count); + [styleLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop) { + layerIDs.push_back(identifier.UTF8String); + }]; + optionalLayerIDs = layerIDs; + } + + std::vector<mbgl::Feature> features = _mbglMap->queryRenderedFeatures(screenBox, optionalLayerIDs); + return MGLFeaturesFromMBGLFeatures(features); +} + #pragma mark Interface Builder methods - (void)prepareForInterfaceBuilder { diff --git a/platform/osx/src/Mapbox.h b/platform/osx/src/Mapbox.h index a98aea9bcf..e4545e04bc 100644 --- a/platform/osx/src/Mapbox.h +++ b/platform/osx/src/Mapbox.h @@ -12,6 +12,7 @@ FOUNDATION_EXPORT const unsigned char MapboxVersionString[]; #import "MGLClockDirectionFormatter.h" #import "MGLCompassDirectionFormatter.h" #import "MGLCoordinateFormatter.h" +#import "MGLFeature.h" #import "MGLGeometry.h" #import "MGLMapCamera.h" #import "MGLMapView.h" @@ -26,6 +27,7 @@ FOUNDATION_EXPORT const unsigned char MapboxVersionString[]; #import "MGLPolygon.h" #import "MGLPolyline.h" #import "MGLShape.h" +#import "MGLShapeCollection.h" #import "MGLStyle.h" #import "MGLTilePyramidOfflineRegion.h" #import "MGLTypes.h" |