diff --git a/platform/darwin/src/MGLFeature.h b/platform/darwin/src/MGLFeature.h new file mode 100644 index 00000000000..69cff6b0541 --- /dev/null +++ b/platform/darwin/src/MGLFeature.h @@ -0,0 +1,137 @@ +#import + +#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 + tile sources. + 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 ordinary `MGLAnnotation` objects, some kinds of `MGLFeature` + objects can also be added to a map view using `-[MGLMapView addAnnotations:]` + and related methods. + */ +@protocol MGLFeature + +/** + An object that uniquely identifies the feature in its containing + tile source. + + 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 + feature identifier + (`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 + Mapbox Streets + layer reference. + */ +@property (nonatomic, copy, nullable, readonly) id identifier; + +/** + A dictionary of attributes for this feature specified by the + tile source. + + 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: + + + + + + + + + + + + +
In the tile sourceIn this dictionary
Null NSNull
Boolean NSNumber (use the boolValue property)
Integer NSNumber (use the unsignedLongLongValue or longLongValue property)
Floating-point number NSNumber (use the doubleValue property)
String NSString
+ + For details about the attribute names and values found in Mapbox-provided + vector tile sources, consult the + Mapbox Streets + and + Mapbox Terrain + 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 + tile source. + */ +@interface MGLPointFeature : MGLPointAnnotation +@end + +/** + The `MGLPolylineFeature` class represents a polyline in a + tile source. + */ +@interface MGLPolylineFeature : MGLPolyline +@end + +/** + The `MGLPolygonFeature` class represents a polygon in a + tile source. + */ +@interface MGLPolygonFeature : MGLPolygon +@end + +/** + The `MGLMultiPointFeature` class represents a multipoint in a + tile source. + */ +@interface MGLMultiPointFeature : MGLMultiPoint +@end + +/** + The `MGLMultiPolylineFeature` class represents a multipolyline in a + tile source. + */ +@interface MGLMultiPolylineFeature : MGLMultiPolyline +@end + +/** + The `MGLMultiPolygonFeature` class represents a multipolygon in a + tile source. + */ +@interface MGLMultiPolygonFeature : MGLMultiPolygon +@end + +/** + The `MGLShapeCollectionFeature` class represents a shape collection in a + tile source. + */ +@interface MGLShapeCollectionFeature : MGLShapeCollection +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm new file mode 100644 index 00000000000..777b296303e --- /dev/null +++ b/platform/darwin/src/MGLFeature.mm @@ -0,0 +1,269 @@ +#import "MGLFeature_Private.h" + +#import "MGLPointAnnotation.h" +#import "MGLPolyline.h" +#import "MGLPolygon.h" + +#import "MGLMultiPoint_Private.h" + +#import + +@protocol MGLFeaturePrivate + +@property (nonatomic, copy, nullable, readwrite) id identifier; +@property (nonatomic, copy, readwrite) NS_DICTIONARY_OF(NSString *, id) *attributes; + +@end + +@interface MGLPointFeature () +@end + +@implementation MGLPointFeature + +@synthesize identifier; +@synthesize attributes; + +- (id)attributeForKey:(NSString *)key { + return self.attributes[key]; +} + +@end + +@interface MGLPolylineFeature () +@end + +@implementation MGLPolylineFeature + +@synthesize identifier; +@synthesize attributes; + +- (id)attributeForKey:(NSString *)key { + return self.attributes[key]; +} + +@end + +@interface MGLPolygonFeature () +@end + +@implementation MGLPolygonFeature + +@synthesize identifier; +@synthesize attributes; + +- (id)attributeForKey:(NSString *)key { + return self.attributes[key]; +} + +@end + +@interface MGLMultiPointFeature () +@end + +@implementation MGLMultiPointFeature + +@synthesize identifier; +@synthesize attributes; + +- (id)attributeForKey:(NSString *)key { + return self.attributes[key]; +} + +@end + +@interface MGLMultiPolylineFeature () +@end + +@implementation MGLMultiPolylineFeature + +@synthesize identifier; +@synthesize attributes; + +- (id)attributeForKey:(NSString *)key { + return self.attributes[key]; +} + +@end + +@interface MGLMultiPolygonFeature () +@end + +@implementation MGLMultiPolygonFeature + +@synthesize identifier; +@synthesize attributes; + +- (id)attributeForKey:(NSString *)key { + return self.attributes[key]; +} + +@end + +@interface MGLShapeCollectionFeature () +@end + +@implementation MGLShapeCollectionFeature + +@synthesize identifier; +@synthesize attributes; + +- (id)attributeForKey:(NSString *)key { + return self.attributes[key]; +} + +@end + +/** + Recursively transforms a C++ type into the corresponding Foundation type. + */ +class PropertyValueEvaluator { +public: + 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 &values) const { + NSMutableArray *objects = [NSMutableArray arrayWithCapacity:values.size()]; + for (const auto &v : values) { + [objects addObject:mbgl::Value::visit(v, *this)]; + } + return objects; + } + + id operator()(const std::unordered_map &items) const { + NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:items.size()]; + for (auto &item : items) { + attributes[@(item.first.c_str())] = mbgl::Value::visit(item.second, *this); + } + return attributes; + } +}; + +/** + Transforms an `mbgl::geometry::geometry` type into an instance of the + corresponding Objective-C geometry class. + */ +template +class GeometryEvaluator { +public: + MGLShape * operator()(const mbgl::Point &geometry) const { + MGLPointFeature *feature = [[MGLPointFeature alloc] init]; + feature.coordinate = toLocationCoordinate2D(geometry); + return feature; + } + + MGLShape * operator()(const mbgl::LineString &geometry) const { + std::vector coordinates = toLocationCoordinates2D(geometry); + return [MGLPolylineFeature polylineWithCoordinates:&coordinates[0] count:coordinates.size()]; + } + + MGLShape * operator()(const mbgl::Polygon &geometry) const { + return toShape(geometry); + } + + MGLShape * operator()(const mbgl::MultiPoint &geometry) const { + std::vector coordinates = toLocationCoordinates2D(geometry); + return [[MGLMultiPointFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()]; + } + + MGLShape * operator()(const mbgl::MultiLineString &geometry) const { + NSMutableArray *polylines = [NSMutableArray arrayWithCapacity:geometry.size()]; + for (auto &lineString : geometry) { + std::vector coordinates = toLocationCoordinates2D(lineString); + MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:&coordinates[0] count:coordinates.size()]; + [polylines addObject:polyline]; + } + + return [MGLMultiPolylineFeature multiPolylineWithPolylines:polylines]; + } + + MGLShape * operator()(const mbgl::MultiPolygon &geometry) const { + NSMutableArray *polygons = [NSMutableArray arrayWithCapacity:geometry.size()]; + for (auto &polygon : geometry) { + [polygons addObject:toShape(polygon)]; + } + + return [MGLMultiPolygonFeature multiPolygonWithPolygons:polygons]; + } + + MGLShape * operator()(const mapbox::geometry::geometry_collection &collection) const { + NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:collection.size()]; + for (auto &geometry : collection) { + // This is very much like the transformation that happens in MGLFeaturesFromMBGLFeatures(), but these are raw geometries with no associated feature IDs or attributes. + MGLShape *shape = mapbox::geometry::geometry::visit(geometry, *this); + [shapes addObject:shape]; + } + return [MGLShapeCollectionFeature shapeCollectionWithShapes:shapes]; + } + +private: + static CLLocationCoordinate2D toLocationCoordinate2D(const mbgl::Point &point) { + return CLLocationCoordinate2DMake(point.y, point.x); + } + + static std::vector toLocationCoordinates2D(const std::vector> &points) { + std::vector coordinates; + coordinates.reserve(points.size()); + std::transform(points.begin(), points.end(), std::back_inserter(coordinates), toLocationCoordinate2D); + return coordinates; + } + + template + static U *toShape(const mbgl::Polygon &geometry) { + auto &linearRing = geometry.front(); + std::vector coordinates = toLocationCoordinates2D(linearRing); + NSMutableArray *innerPolygons; + if (geometry.size() > 1) { + innerPolygons = [NSMutableArray arrayWithCapacity:geometry.size() - 1]; + for (auto iter = geometry.begin() + 1; iter != geometry.end(); iter++) { + auto &innerRing = *iter; + std::vector coordinates = toLocationCoordinates2D(innerRing); + MGLPolygon *innerPolygon = [MGLPolygon polygonWithCoordinates:&coordinates[0] count:coordinates.size()]; + [innerPolygons addObject:innerPolygon]; + } + } + + return [U polygonWithCoordinates:&coordinates[0] count:coordinates.size() interiorPolygons:innerPolygons]; + } +}; + +NS_ARRAY_OF(MGLShape *) *MGLFeaturesFromMBGLFeatures(const std::vector &features) { + NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:features.size()]; + for (const auto &feature : features) { + NSMutableDictionary *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); + } + + GeometryEvaluator evaluator; + MGLShape *shape = mapbox::geometry::geometry::visit(feature.geometry, evaluator); + if (feature.id) { + shape.identifier = @(*feature.id); + } + shape.attributes = attributes; + [shapes addObject:shape]; + } + return shapes; +} diff --git a/platform/darwin/src/MGLFeature_Private.h b/platform/darwin/src/MGLFeature_Private.h new file mode 100644 index 00000000000..fbc7f88559c --- /dev/null +++ b/platform/darwin/src/MGLFeature_Private.h @@ -0,0 +1,11 @@ +#import "MGLFeature.h" +#import "MGLShape.h" + +#import +#import + +/** + Returns an array of `MGLFeature` objects converted from the given vector of + vector tile features. + */ +NS_ARRAY_OF(MGLShape *) *MGLFeaturesFromMBGLFeatures(const std::vector &features); diff --git a/platform/darwin/src/MGLMultiPoint.h b/platform/darwin/src/MGLMultiPoint.h index 041c52e8f2c..2d6b3270861 100644 --- a/platform/darwin/src/MGLMultiPoint.h +++ b/platform/darwin/src/MGLMultiPoint.h @@ -17,7 +17,10 @@ NS_ASSUME_NONNULL_BEGIN */ @interface MGLMultiPoint : MGLShape -/** The number of points associated with the shape. (read-only) */ +/** The array of coordinates associated with the shape. */ +@property (nonatomic, readonly) CLLocationCoordinate2D *coordinates NS_RETURNS_INNER_POINTER; + +/** The number of coordinates associated with the shape. (read-only) */ @property (nonatomic, readonly) NSUInteger pointCount; /** diff --git a/platform/darwin/src/MGLMultiPoint.mm b/platform/darwin/src/MGLMultiPoint.mm index a864b7bce7f..aaf84472749 100644 --- a/platform/darwin/src/MGLMultiPoint.mm +++ b/platform/darwin/src/MGLMultiPoint.mm @@ -14,7 +14,6 @@ @implementation MGLMultiPoint { - CLLocationCoordinate2D *_coords; size_t _count; MGLCoordinateBounds _bounds; } @@ -27,13 +26,13 @@ - (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords if (self) { _count = count; - _coords = (CLLocationCoordinate2D *)malloc(_count * sizeof(CLLocationCoordinate2D)); + _coordinates = (CLLocationCoordinate2D *)malloc(_count * sizeof(CLLocationCoordinate2D)); mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty(); for (NSUInteger i = 0; i < _count; i++) { - _coords[i] = coords[i]; + _coordinates[i] = coords[i]; bounds.extend(mbgl::LatLng(coords[i].latitude, coords[i].longitude)); } @@ -45,7 +44,7 @@ - (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords - (void)dealloc { - free(_coords); + free(_coordinates); } - (CLLocationCoordinate2D)coordinate @@ -59,7 +58,7 @@ - (CLLocationCoordinate2D)coordinate assert(_count > 0); - return CLLocationCoordinate2DMake(_coords[0].latitude, _coords[0].longitude); + return CLLocationCoordinate2DMake(_coordinates[0].latitude, _coordinates[0].longitude); } - (NSUInteger)pointCount @@ -89,7 +88,7 @@ - (void)getCoordinates:(CLLocationCoordinate2D *)coords range:(NSRange)range for (NSUInteger i = range.location; i < range.location + range.length; i++) { - coords[index] = _coords[i]; + coords[index] = _coordinates[i]; index++; } } @@ -104,24 +103,16 @@ - (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds return MGLLatLngBoundsFromCoordinateBounds(_bounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds)); } -- (void)addShapeAnnotationObjectToCollection:(std::vector &)shapes withDelegate:(id )delegate { +- (mbgl::AnnotationSegments)annotationSegments { NSUInteger count = self.pointCount; - if (count == 0) { - return; - } - - CLLocationCoordinate2D *coordinates = (CLLocationCoordinate2D *)malloc(count * sizeof(CLLocationCoordinate2D)); - NSAssert(coordinates, @"Unable to allocate annotation with %lu points", (unsigned long)count); - [self getCoordinates:coordinates range:NSMakeRange(0, count)]; + CLLocationCoordinate2D *coordinates = self.coordinates; mbgl::AnnotationSegment segment; segment.reserve(count); for (NSUInteger i = 0; i < count; i++) { segment.push_back(MGLLatLngFromLocationCoordinate2D(coordinates[i])); } - free(coordinates); - shapes.emplace_back(mbgl::AnnotationSegments {{ segment }}, - [self shapeAnnotationPropertiesObjectWithDelegate:delegate]); + return { segment }; } - (mbgl::ShapeAnnotation::Properties)shapeAnnotationPropertiesObjectWithDelegate:(__unused id )delegate { diff --git a/platform/darwin/src/MGLMultiPoint_Private.h b/platform/darwin/src/MGLMultiPoint_Private.h index c1f1fa15844..2c1e0b7222d 100644 --- a/platform/darwin/src/MGLMultiPoint_Private.h +++ b/platform/darwin/src/MGLMultiPoint_Private.h @@ -21,8 +21,8 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count; - (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds; -/** Adds a shape annotation to the given vector by asking the delegate for style values. */ -- (void)addShapeAnnotationObjectToCollection:(std::vector &)shapes withDelegate:(id )delegate; +/** Returns the shape’s annotation segments. */ +- (mbgl::AnnotationSegments)annotationSegments; /** Constructs a shape annotation properties object by asking the delegate for style values. */ - (mbgl::ShapeAnnotation::Properties)shapeAnnotationPropertiesObjectWithDelegate:(id )delegate; diff --git a/platform/darwin/src/MGLPolygon.h b/platform/darwin/src/MGLPolygon.h index 1a158874bb9..3d5b36abb62 100644 --- a/platform/darwin/src/MGLPolygon.h +++ b/platform/darwin/src/MGLPolygon.h @@ -16,6 +16,17 @@ NS_ASSUME_NONNULL_BEGIN */ @interface MGLPolygon : MGLMultiPoint +/** + The array of polygons nested inside the receiver. + + The area occupied by any interior polygons is excluded from the overall shape. + Interior polygons should not overlap. An interior polygon should not have + interior polygons of its own. + + If there are no interior polygons, the value of this property is `nil`. + */ +@property (nonatomic, nullable, readonly) NS_ARRAY_OF(MGLPolygon *) *interiorPolygons; + /** Creates and returns an `MGLPolygon` object from the specified set of coordinates. @@ -25,8 +36,48 @@ NS_ASSUME_NONNULL_BEGIN @param count The number of items in the `coords` array. @return A new polygon object. */ -+ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords - count:(NSUInteger)count; ++ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count; + +/** + Creates and returns an `MGLPolygon` object from the specified set of + coordinates and interior polygons. + + @param coords The array of coordinates defining the shape. The data in this + array is copied to the new object. + @param count The number of items in the `coords` array. + @param interiorPolygons An array of `MGLPolygon` objects that define regions + excluded from the overall shape. If this array is `nil` or empty, the shape + is considered to have no interior polygons. + @return A new polygon object. + */ ++ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count interiorPolygons:(nullable NS_ARRAY_OF(MGLPolygon *) *)interiorPolygons; + +@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. + + @note `MGLMultiPolygon` objects cannot be added to a map view using + `-[MGLMapView addAnnotations:]` and related methods. + */ +@interface MGLMultiPolygon : MGLShape + +/** + 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 diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm index 5019385cb20..5a24cb07917 100644 --- a/platform/darwin/src/MGLPolygon.mm +++ b/platform/darwin/src/MGLPolygon.mm @@ -1,15 +1,36 @@ #import "MGLPolygon.h" #import "MGLMultiPoint_Private.h" +#import "MGLGeometry_Private.h" @implementation MGLPolygon @dynamic overlayBounds; -+ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords - count:(NSUInteger)count -{ - return [[self alloc] initWithCoordinates:coords count:count]; ++ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count { + return [self polygonWithCoordinates:coords count:count interiorPolygons:nil]; +} + ++ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count interiorPolygons:(NSArray *)interiorPolygons { + return [[self alloc] initWithCoordinates:coords count:count interiorPolygons:interiorPolygons]; +} + +- (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count interiorPolygons:(NSArray *)interiorPolygons { + if (self = [super initWithCoordinates:coords count:count]) { + if (interiorPolygons.count) { + _interiorPolygons = interiorPolygons; + } + } + return self; +} + +- (mbgl::AnnotationSegments)annotationSegments { + auto segments = super.annotationSegments; + for (MGLPolygon *polygon in self.interiorPolygons) { + auto interiorSegments = polygon.annotationSegments; + segments.push_back(interiorSegments.front()); + } + return segments; } - (mbgl::ShapeAnnotation::Properties)shapeAnnotationPropertiesObjectWithDelegate:(id )delegate { @@ -26,3 +47,39 @@ + (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords } @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 5e455137354..78d96497514 100644 --- a/platform/darwin/src/MGLPolyline.h +++ b/platform/darwin/src/MGLPolyline.h @@ -30,4 +30,31 @@ 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. + + @note `MGLMultiPolyline` objects cannot be added to a map view using + `-[MGLMapView addAnnotations:]` and related methods. + */ +@interface MGLMultiPolyline : MGLShape + +/** + 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 f560a571bce..810b359bb09 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 @@ + (instancetype)polylineWithCoordinates:(CLLocationCoordinate2D *)coords } @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 00000000000..a617223ea75 --- /dev/null +++ b/platform/darwin/src/MGLShapeCollection.h @@ -0,0 +1,35 @@ +#import + +#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. + + @note `MGLShapeCollection` objects cannot be added to a map view using + `-[MGLMapView addAnnotations:]` and related methods. + */ +@interface MGLShapeCollection : MGLShape + +/** + An array of shapes forming the shape collection. + */ +@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLShape *) *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 *) *)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 00000000000..5d42b5a51ca --- /dev/null +++ b/platform/darwin/src/MGLShapeCollection.m @@ -0,0 +1,21 @@ +#import "MGLShapeCollection.h" + +@implementation MGLShapeCollection + ++ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes { + return [[self alloc] initWithShapes:shapes]; +} + +- (instancetype)initWithShapes:(NS_ARRAY_OF(MGLShape *) *)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/darwin/test/MGLFeatureTests.mm b/platform/darwin/test/MGLFeatureTests.mm new file mode 100644 index 00000000000..6cf038d4fb0 --- /dev/null +++ b/platform/darwin/test/MGLFeatureTests.mm @@ -0,0 +1,160 @@ +#import +#import + +#import "../../darwin/src/MGLFeature_Private.h" + +@interface MGLFeatureTests : XCTestCase + +@end + +@implementation MGLFeatureTests + +- (void)testGeometryConversion { + std::vector features; + + mapbox::geometry::point point = { -90.066667, 29.95 }; + features.emplace_back(point); + + mapbox::geometry::line_string lineString = { + { -84.516667, 39.1 }, + { -90.066667, 29.95 }, + }; + features.emplace_back(lineString); + + mapbox::geometry::polygon polygon = { + { + { 1, 1 }, + { 4, 1 }, + { 4, 4 }, + { 1, 4 }, + }, + { + { 2, 2 }, + { 3, 2 }, + { 3, 3 }, + { 2, 3 }, + }, + }; + features.emplace_back(polygon); + + NS_ARRAY_OF(MGLShape *) *shapes = MGLFeaturesFromMBGLFeatures(features); + XCTAssertEqual(shapes.count, 3, @"All features should be converted into shapes"); + + MGLPointFeature *pointShape = (MGLPointFeature *)shapes[0]; + XCTAssertTrue([pointShape isKindOfClass:[MGLPointFeature class]]); + XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:pointShape.coordinate], + [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(29.95, -90.066667)]); + + MGLPolylineFeature *polylineShape = (MGLPolylineFeature *)shapes[1]; + XCTAssertTrue([polylineShape isKindOfClass:[MGLPolylineFeature class]]); + XCTAssertEqual(polylineShape.pointCount, 2); + CLLocationCoordinate2D polylineCoordinates[2]; + [polylineShape getCoordinates:polylineCoordinates range:NSMakeRange(0, polylineShape.pointCount)]; + XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:polylineCoordinates[0]], + [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(39.1, -84.516667)]); + XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:polylineCoordinates[1]], + [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(29.95, -90.066667)]); + + MGLPolygonFeature *polygonShape = (MGLPolygonFeature *)shapes[2]; + XCTAssertTrue([polygonShape isKindOfClass:[MGLPolygonFeature class]]); + XCTAssertEqual(polygonShape.pointCount, 4); + CLLocationCoordinate2D *polygonCoordinates = polygonShape.coordinates; + XCTAssertNotEqual(polygonCoordinates, nil); + XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:polygonCoordinates[0]], + [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(1, 1)]); + XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:polygonCoordinates[1]], + [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(1, 4)]); + XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:polygonCoordinates[2]], + [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(4, 4)]); + XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:polygonCoordinates[3]], + [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(4, 1)]); + NS_ARRAY_OF(MGLPolygon *) *interiorPolygons = polygonShape.interiorPolygons; + XCTAssertEqual(interiorPolygons.count, 1); + MGLPolygon *interiorPolygon = interiorPolygons.firstObject; + XCTAssertEqual(interiorPolygon.pointCount, 4); + CLLocationCoordinate2D interiorPolygonCoordinates[4]; + [interiorPolygon getCoordinates:interiorPolygonCoordinates range:NSMakeRange(0, interiorPolygon.pointCount)]; + XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:interiorPolygonCoordinates[0]], + [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(2, 2)]); + XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:interiorPolygonCoordinates[1]], + [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(2, 3)]); + XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:interiorPolygonCoordinates[2]], + [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(3, 3)]); + XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:interiorPolygonCoordinates[3]], + [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(3, 2)]); +} + +- (void)testPropertyConversion { + std::vector features; + + mapbox::geometry::point point = { -90.066667, 29.95 }; + mbgl::Feature pointFeature(point); + pointFeature.id = UINT64_MAX; + pointFeature.properties["null"] = nullptr; + pointFeature.properties["bool"] = true; + pointFeature.properties["unsigned int"] = UINT64_MAX; + pointFeature.properties["int"] = INT64_MIN; + pointFeature.properties["double"] = DBL_MAX; + pointFeature.properties["string"] = std::string("🚏"); + std::vector vector; + vector.push_back(true); + vector.push_back(false); + vector.push_back(true); + features.push_back(pointFeature); + + NS_ARRAY_OF(MGLShape *) *shapes = MGLFeaturesFromMBGLFeatures(features); + XCTAssertEqual(shapes.count, 1, @"All features should be converted into shapes"); + + MGLShape *shape = shapes.firstObject; + XCTAssertTrue([shape conformsToProtocol:@protocol(MGLFeature)]); + XCTAssertTrue([shape isKindOfClass:[MGLShape class]]); + + NSNumber *identifier = shape.identifier; + XCTAssertTrue([identifier isKindOfClass:[NSNumber class]], @"Feature identifier should be NSNumber"); + XCTAssertEqual(strcmp(identifier.objCType, @encode(uint64_t)), 0, @"Feature identifier should be 64-bit unsigned integer"); + + NSNull *null = [shape attributeForKey:@"null"]; + XCTAssertNotNil(null); + XCTAssertTrue([null isKindOfClass:[NSNull class]]); + XCTAssertEqual(null, shape.attributes[@"null"]); + + NSNumber *boolean = [shape attributeForKey:@"bool"]; + XCTAssertNotNil(boolean); + XCTAssertTrue([boolean isKindOfClass:[NSNumber class]]); +#if (TARGET_OS_IPHONE && __LP64__) || TARGET_OS_WATCH + XCTAssertEqual(strcmp(boolean.objCType, @encode(char)), 0, @"Boolean property should be converted to bool NSNumber"); +#else + XCTAssertEqual(strcmp(boolean.objCType, @encode(BOOL)), 0, @"Boolean property should be converted to bool NSNumber"); +#endif + XCTAssertTrue(boolean.boolValue); + XCTAssertEqual(boolean, shape.attributes[@"bool"]); + + NSNumber *unsignedInteger = [shape attributeForKey:@"unsigned int"]; + XCTAssertNotNil(unsignedInteger); + XCTAssertTrue([unsignedInteger isKindOfClass:[NSNumber class]]); + XCTAssertEqual(strcmp(unsignedInteger.objCType, @encode(uint64_t)), 0, @"Unsigned integer property should be converted to unsigned long long NSNumber"); + XCTAssertEqual(unsignedInteger.unsignedLongLongValue, UINT64_MAX); + XCTAssertEqual(unsignedInteger, shape.attributes[@"unsigned int"]); + + NSNumber *integer = [shape attributeForKey:@"int"]; + XCTAssertNotNil(integer); + XCTAssertTrue([integer isKindOfClass:[NSNumber class]]); + XCTAssertEqual(strcmp(integer.objCType, @encode(int64_t)), 0, @"Integer property should be converted to long long NSNumber"); + XCTAssertEqual(integer.longLongValue, INT64_MIN); + XCTAssertEqual(integer, shape.attributes[@"int"]); + + NSNumber *floatingPointNumber = [shape attributeForKey:@"double"]; + XCTAssertNotNil(floatingPointNumber); + XCTAssertTrue([floatingPointNumber isKindOfClass:[NSNumber class]]); + XCTAssertEqual(strcmp(floatingPointNumber.objCType, @encode(double)), 0, @"Floating-point number property should be converted to double NSNumber"); + XCTAssertEqual(floatingPointNumber.doubleValue, DBL_MAX); + XCTAssertEqual(floatingPointNumber, shape.attributes[@"double"]); + + NSString *string = [shape attributeForKey:@"string"]; + XCTAssertNotNil(string); + XCTAssertTrue([string isKindOfClass:[NSString class]]); + XCTAssertEqualObjects(string, @"🚏"); + XCTAssertEqual(string, shape.attributes[@"string"]); +} + +@end diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 012688ab17f..65b8eb74b46 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -10,6 +10,8 @@ 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, along with additional classes to represent complex geometry in that data. ([#5110](https://github.com/mapbox/mapbox-gl-native/pull/5110)) +- An MGLPolygon can now have interior polygons, representing holes knocked out of the overall shape. ([#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 13b4fbffece..c72bdfd0f86 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -306,6 +306,22 @@ - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSIn free(polygonCoordinates); } + + CLLocationCoordinate2D innerCoordinates[] = { + CLLocationCoordinate2DMake(-5, -5), + CLLocationCoordinate2DMake(-5, 5), + CLLocationCoordinate2DMake(5, 5), + CLLocationCoordinate2DMake(5, -5), + }; + MGLPolygon *innerPolygon = [MGLPolygon polygonWithCoordinates:innerCoordinates count:sizeof(innerCoordinates) / sizeof(innerCoordinates[0])]; + CLLocationCoordinate2D outerCoordinates[] = { + CLLocationCoordinate2DMake(-10, -20), + CLLocationCoordinate2DMake(-10, 10), + CLLocationCoordinate2DMake(10, 10), + CLLocationCoordinate2DMake(10, -10), + }; + MGLPolygon *outerPolygon = [MGLPolygon polygonWithCoordinates:outerCoordinates count:sizeof(outerCoordinates) / sizeof(outerCoordinates[0]) interiorPolygons:@[innerPolygon]]; + [self.mapView addAnnotation:outerPolygon]; } else if (buttonIndex == actionSheet.firstOtherButtonIndex + 10) { @@ -395,13 +411,22 @@ - (IBAction)handleLongPress:(UILongPressGestureRecognizer *)longPress { 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 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 cf48b869e37..811fb89b7da 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 4018B1CA1CDC288E00F666AF /* MGLAnnotationView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4018B1CB1CDC288E00F666AF /* MGLAnnotationView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 40FDA76B1CCAAA6800442548 /* MBXAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40FDA76A1CCAAA6800442548 /* MBXAnnotationView.m */; }; + DA0CD5901CF56F6A00A5F5A5 /* MGLFeatureTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */; }; DA17BE301CC4BAC300402C41 /* MGLMapView_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = DA17BE2F1CC4BAC300402C41 /* MGLMapView_Internal.h */; }; DA17BE311CC4BDAA00402C41 /* MGLMapView_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = DA17BE2F1CC4BAC300402C41 /* MGLMapView_Internal.h */; }; DA1DC96A1CB6C6B7006E619F /* MBXCustomCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA1DC9671CB6C6B7006E619F /* MBXCustomCalloutView.m */; }; @@ -228,6 +229,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 */ @@ -316,6 +326,7 @@ 402E9DE01CD2C76200FD4519 /* Mapbox.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Mapbox.playground; sourceTree = ""; }; 40FDA7691CCAAA6800442548 /* MBXAnnotationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBXAnnotationView.h; sourceTree = ""; }; 40FDA76A1CCAAA6800442548 /* MBXAnnotationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBXAnnotationView.m; sourceTree = ""; }; + DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLFeatureTests.mm; path = ../../darwin/test/MGLFeatureTests.mm; sourceTree = ""; }; DA17BE2F1CC4BAC300402C41 /* MGLMapView_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapView_Internal.h; sourceTree = ""; }; DA1DC94A1CB6C1C2006E619F /* Mapbox GL.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mapbox GL.app"; sourceTree = BUILT_PRODUCTS_DIR; }; DA1DC9501CB6C1C2006E619F /* MBXAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBXAppDelegate.h; sourceTree = ""; }; @@ -474,6 +485,11 @@ DABCABC01CB80717000A7C39 /* locations.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = locations.hpp; sourceTree = ""; }; DAC07C961CBB2CD6000CB309 /* mbgl.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = mbgl.xcconfig; path = ../../build/ios/mbgl.xcconfig; sourceTree = ""; }; DAC49C621CD07D74009E1AA3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = ""; }; + DAD165691CF41981001FF4B9 /* MGLFeature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature.h; sourceTree = ""; }; + DAD1656A1CF41981001FF4B9 /* MGLFeature_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature_Private.h; sourceTree = ""; }; + DAD1656B1CF41981001FF4B9 /* MGLFeature.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFeature.mm; sourceTree = ""; }; + DAD165761CF4CDFF001FF4B9 /* MGLShapeCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeCollection.h; sourceTree = ""; }; + DAD165771CF4CDFF001FF4B9 /* MGLShapeCollection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLShapeCollection.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -624,6 +640,7 @@ DA35A2C31CCA9F8300E826B2 /* MGLClockDirectionFormatterTests.m */, DA35A2C41CCA9F8300E826B2 /* MGLCompassDirectionFormatterTests.m */, DA35A2A91CCA058D00E826B2 /* MGLCoordinateFormatterTests.m */, + DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */, DA2E885C1CC0382C00F24E7B /* MGLGeometryTests.mm */, DA2E885D1CC0382C00F24E7B /* MGLOfflinePackTests.m */, DA2E885E1CC0382C00F24E7B /* MGLOfflineRegionTests.m */, @@ -654,56 +671,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 +693,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 +820,114 @@ name = Configuration; sourceTree = ""; }; + 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 = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + 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 = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -894,6 +964,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 +976,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 +989,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 +1001,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 +1009,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 */, @@ -1262,6 +1337,7 @@ DA35A2C51CCA9F8300E826B2 /* MGLClockDirectionFormatterTests.m in Sources */, DA2E88621CC0382C00F24E7B /* MGLOfflinePackTests.m in Sources */, DA35A2AA1CCA058D00E826B2 /* MGLCoordinateFormatterTests.m in Sources */, + DA0CD5901CF56F6A00A5F5A5 /* MGLFeatureTests.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1270,12 +1346,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 +1386,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 */, @@ -1583,6 +1663,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", + "$(variant_cflags)", "$(geometry_cflags)", ); PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test; @@ -1600,6 +1681,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", + "$(variant_cflags)", "$(geometry_cflags)", ); PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test; diff --git a/platform/ios/jazzy.yml b/platform/ios/jazzy.yml index f6a5cfba4b4..61570994d5e 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 3f54b07f41f..ca0584c8211 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) { @@ -880,6 +881,11 @@ IB_DESIGNABLE /** Adds an annotation to the map view. + @note `MGLMultiPolyline`, `MGLMultiPolygon`, and `MGLShapeCollection` objects + cannot be added to the map view at this time. Any multipolyline, + multipolygon, or shape collection object that is passed into this method is + silently ignored. + @param annotation The annotation object to add to the receiver. This object must conform to the `MGLAnnotation` protocol. The map view retains the annotation object. */ @@ -888,6 +894,11 @@ IB_DESIGNABLE /** Adds an array of annotations to the map view. + @note `MGLMultiPolyline`, `MGLMultiPolygon`, and `MGLShapeCollection` objects + cannot be added to the map view at this time. Any multipolyline, + multipolygon, or shape collection objects that are passed in are silently + ignored. + @param annotations An array of annotation objects. Each object in the array must conform to the `MGLAnnotation` protocol. The map view retains each individual annotation object. @@ -1021,6 +1032,132 @@ IB_DESIGNABLE */ - (void)removeOverlays:(NS_ARRAY_OF(id ) *)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 ) *)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 + tile sources. + 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 + Mapbox Streets source, + 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 + Mapbox Studio. + + @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 ) *)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 ) *)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 + tile sources. + 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 + Mapbox Streets source, + 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 + Mapbox Studio. + + @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 ) *)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 b9acdfb1d59..59830b094f5 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -26,6 +26,7 @@ #include #import "Mapbox.h" +#import "MGLFeature_Private.h" #import "MGLGeometry_Private.h" #import "MGLMultiPoint_Private.h" #import "MGLOfflineStorage_Private.h" @@ -2811,9 +2812,20 @@ - (void)addAnnotations:(NS_ARRAY_OF(id ) *)annotations if ([annotation isKindOfClass:[MGLMultiPoint class]]) { - [(MGLMultiPoint *)annotation addShapeAnnotationObjectToCollection:shapes withDelegate:self]; + // The multipoint knows how to style itself (with the map view’s help). + MGLMultiPoint *multiPoint = (MGLMultiPoint *)annotation; + if (!multiPoint.pointCount) { + continue; + } + shapes.emplace_back(multiPoint.annotationSegments, [multiPoint shapeAnnotationPropertiesObjectWithDelegate:self]); [userShapes addObject:annotation]; } + else if ([annotation isKindOfClass:[MGLMultiPolyline class]] + || [annotation isKindOfClass:[MGLMultiPolygon class]] + || [annotation isKindOfClass:[MGLShapeCollection class]]) + { + continue; + } else { MGLAnnotationView *annotationView; @@ -4184,6 +4196,57 @@ - (void)updateHeadingForDeviceOrientation } } +#pragma mark Data + +- (NS_ARRAY_OF(id ) *)visibleFeaturesAtPoint:(CGPoint)point +{ + return [self visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:nil]; +} + +- (NS_ARRAY_OF(id ) *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers +{ + mbgl::ScreenCoordinate screenCoordinate = { point.x, point.y }; + + mbgl::optional> optionalLayerIDs; + if (styleLayerIdentifiers) + { + __block std::vector layerIDs; + layerIDs.reserve(styleLayerIdentifiers.count); + [styleLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop) + { + layerIDs.push_back(identifier.UTF8String); + }]; + optionalLayerIDs = layerIDs; + } + + std::vector features = _mbglMap->queryRenderedFeatures(screenCoordinate, optionalLayerIDs); + return MGLFeaturesFromMBGLFeatures(features); +} + +- (NS_ARRAY_OF(id ) *)visibleFeaturesInRect:(CGRect)rect { + return [self visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:nil]; +} + +- (NS_ARRAY_OF(id ) *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers { + mbgl::ScreenBox screenBox = { + { CGRectGetMinX(rect), CGRectGetMinY(rect) }, + { CGRectGetMaxX(rect), CGRectGetMaxY(rect) }, + }; + + mbgl::optional> optionalLayerIDs; + if (styleLayerIdentifiers) { + __block std::vector layerIDs; + layerIDs.reserve(styleLayerIdentifiers.count); + [styleLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop) { + layerIDs.push_back(identifier.UTF8String); + }]; + optionalLayerIDs = layerIDs; + } + + std::vector 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 3b7361a7562..013bb816140 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 67bdce1e6c8..f2e1be966f5 100644 --- a/platform/osx/CHANGELOG.md +++ b/platform/osx/CHANGELOG.md @@ -3,6 +3,8 @@ ## 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, along with additional classes to represent complex geometry in that data. ([#5110](https://github.com/mapbox/mapbox-gl-native/pull/5110)) +* An MGLPolygon can now have interior polygons, representing holes knocked out of the overall shape. ([#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/Base.lproj/MainMenu.xib b/platform/osx/app/Base.lproj/MainMenu.xib index 4afb3b244e6..c80428ff00b 100644 --- a/platform/osx/app/Base.lproj/MainMenu.xib +++ b/platform/osx/app/Base.lproj/MainMenu.xib @@ -1,5 +1,5 @@ - + diff --git a/platform/osx/app/Base.lproj/MapDocument.xib b/platform/osx/app/Base.lproj/MapDocument.xib index 9a3db47df6a..55d82d21d08 100644 --- a/platform/osx/app/Base.lproj/MapDocument.xib +++ b/platform/osx/app/Base.lproj/MapDocument.xib @@ -1,5 +1,5 @@ - + @@ -123,6 +123,12 @@ + + + + + + diff --git a/platform/osx/app/MapDocument.m b/platform/osx/app/MapDocument.m index 9bff4603e41..4274126747f 100644 --- a/platform/osx/app/MapDocument.m +++ b/platform/osx/app/MapDocument.m @@ -14,6 +14,27 @@ { .latitude = -13.15589555, .longitude = -74.2178961777998 }, }; +NS_ARRAY_OF(id ) *MBXFlattenedShapes(NS_ARRAY_OF(id ) *shapes) { + NSMutableArray *flattenedShapes = [NSMutableArray arrayWithCapacity:shapes.count]; + for (id shape in shapes) { + NSArray *subshapes; + if ([shape isKindOfClass:[MGLMultiPolyline class]]) { + subshapes = [(MGLMultiPolyline *)shape polylines]; + } else if ([shape isKindOfClass:[MGLMultiPolygon class]]) { + subshapes = [(MGLMultiPolygon *)shape polygons]; + } else if ([shape isKindOfClass:[MGLShapeCollection class]]) { + subshapes = MBXFlattenedShapes([(MGLShapeCollection *)shape shapes]); + } + + if (subshapes) { + [flattenedShapes addObjectsFromArray:subshapes]; + } else { + [flattenedShapes addObject:shape]; + } + } + return flattenedShapes; +} + @interface MapDocument () @property (weak) IBOutlet NSMenu *mapViewContextMenu; @@ -436,9 +457,17 @@ - (void)dropPinAtPoint:(NSPoint)point { } - (DroppedPinAnnotation *)pinAtPoint:(NSPoint)point { + NSArray *features = [self.mapView visibleFeaturesAtPoint:point]; + NSString *title; + for (id 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)]; @@ -455,6 +484,16 @@ - (void)removePinAtPoint:(NSPoint)point { [self.mapView removeAnnotation:[self.mapView annotationAtPoint:point]]; } +- (IBAction)selectFeatures:(id)sender { + [self selectFeaturesAtPoint:_mouseLocationForMapViewContextMenu]; +} + +- (void)selectFeaturesAtPoint:(NSPoint)point { + NSArray *features = [self.mapView visibleFeaturesAtPoint:point]; + NSArray *flattenedFeatures = MBXFlattenedShapes(features); + [self.mapView addAnnotations:flattenedFeatures]; +} + #pragma mark User interface validation - (BOOL)validateMenuItem:(NSMenuItem *)menuItem { @@ -512,6 +551,9 @@ - (BOOL)validateMenuItem:(NSMenuItem *)menuItem { menuItem.hidden = annotationUnderCursor == nil; return YES; } + if (menuItem.action == @selector(selectFeatures:)) { + return YES; + } if (menuItem.action == @selector(toggleTileBoundaries:)) { BOOL isShown = self.mapView.debugMask & MGLMapDebugTileBoundariesMask; menuItem.title = isShown ? @"Hide Tile Boundaries" : @"Show Tile Boundaries"; @@ -706,6 +748,10 @@ - (void)mapView:(MGLMapView *)mapView didDeselectAnnotation:(id ) } } +- (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 b1aca9bb450..9e160d050fa 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 270b2e33d23..51d9f0671ea 100644 --- a/platform/osx/osx.xcodeproj/project.pbxproj +++ b/platform/osx/osx.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 52BECB0A1CC5A26F009CD791 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52BECB091CC5A26F009CD791 /* SystemConfiguration.framework */; }; + DA0CD58E1CF56F5800A5F5A5 /* MGLFeatureTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA0CD58D1CF56F5800A5F5A5 /* MGLFeatureTests.mm */; }; DA35A2A41CC9EB1A00E826B2 /* MGLCoordinateFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = DA35A2A31CC9EB1A00E826B2 /* MGLCoordinateFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; DA35A2A61CC9EB2700E826B2 /* MGLCoordinateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2A51CC9EB2700E826B2 /* MGLCoordinateFormatter.m */; }; DA35A2A81CC9F41600E826B2 /* MGLCoordinateFormatterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2A71CC9F41600E826B2 /* MGLCoordinateFormatterTests.m */; }; @@ -31,6 +32,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 */; }; @@ -141,6 +147,7 @@ /* Begin PBXFileReference section */ 52BECB091CC5A26F009CD791 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + DA0CD58D1CF56F5800A5F5A5 /* MGLFeatureTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLFeatureTests.mm; path = ../../darwin/test/MGLFeatureTests.mm; sourceTree = ""; }; DA35A2A31CC9EB1A00E826B2 /* MGLCoordinateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCoordinateFormatter.h; sourceTree = ""; }; DA35A2A51CC9EB2700E826B2 /* MGLCoordinateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLCoordinateFormatter.m; sourceTree = ""; }; DA35A2A71CC9F41600E826B2 /* MGLCoordinateFormatterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLCoordinateFormatterTests.m; path = ../../darwin/test/MGLCoordinateFormatterTests.m; sourceTree = ""; }; @@ -167,6 +174,11 @@ DA8933B41CCD2C2500E68420 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Foundation.strings; sourceTree = ""; }; DA8933B71CCD2C2D00E68420 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Foundation.stringsdict; sourceTree = ""; }; DAC2ABC41CC6D343006D18C4 /* MGLAnnotationImage_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationImage_Private.h; sourceTree = ""; }; + DACC22121CF3D3E200D220D9 /* MGLFeature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature.h; sourceTree = ""; }; + DACC22131CF3D3E200D220D9 /* MGLFeature.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFeature.mm; sourceTree = ""; }; + DACC22171CF3D4F700D220D9 /* MGLFeature_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature_Private.h; sourceTree = ""; }; + DAD165721CF4CD7A001FF4B9 /* MGLShapeCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeCollection.h; sourceTree = ""; }; + DAD165731CF4CD7A001FF4B9 /* MGLShapeCollection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLShapeCollection.m; sourceTree = ""; }; DAE6C2E11CC304F900DB3429 /* Credits.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = ""; }; DAE6C2E31CC3050F00DB3429 /* DroppedPinAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DroppedPinAnnotation.h; sourceTree = ""; }; DAE6C2E41CC3050F00DB3429 /* DroppedPinAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DroppedPinAnnotation.m; sourceTree = ""; }; @@ -359,6 +371,80 @@ path = ../../darwin/resources; sourceTree = ""; }; + 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 = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + 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 = ""; + }; DAE6C31E1CC308BC00DB3429 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -390,6 +476,7 @@ DA35A2C11CCA9F4A00E826B2 /* MGLClockDirectionFormatterTests.m */, DA35A2B51CCA14D700E826B2 /* MGLCompassDirectionFormatterTests.m */, DA35A2A71CC9F41600E826B2 /* MGLCoordinateFormatterTests.m */, + DA0CD58D1CF56F5800A5F5A5 /* MGLFeatureTests.mm */, DAE6C3C81CC34BD800DB3429 /* MGLGeometryTests.mm */, DAE6C3C91CC34BD800DB3429 /* MGLOfflinePackTests.m */, DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */, @@ -404,56 +491,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 +556,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 +579,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 +588,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 +771,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 +792,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; @@ -754,6 +809,7 @@ DAE6C3D51CC34C9900DB3429 /* MGLOfflineStorageTests.m in Sources */, DAE6C3D31CC34C9900DB3429 /* MGLOfflinePackTests.m in Sources */, DA35A2A81CC9F41600E826B2 /* MGLCoordinateFormatterTests.m in Sources */, + DA0CD58E1CF56F5800A5F5A5 /* MGLFeatureTests.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1042,6 +1098,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", + "$(variant_cflags)", "$(geometry_cflags)", ); PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test; @@ -1059,6 +1116,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", + "$(variant_cflags)", "$(geometry_cflags)", ); PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test; @@ -1094,6 +1152,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 749b3561d27..5c7e75135ba 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 @@ -533,6 +534,11 @@ IB_DESIGNABLE /** Adds an annotation to the map view. + @note `MGLMultiPolyline`, `MGLMultiPolygon`, and `MGLShapeCollection` objects + cannot be added to the map view at this time. Any multipolyline, + multipolygon, or shape collection object that is passed into this method is + silently ignored. + @param annotation The annotation object to add to the receiver. This object must conform to the `MGLAnnotation` protocol. The map view retains the annotation object. @@ -542,6 +548,11 @@ IB_DESIGNABLE /** Adds an array of annotations to the map view. + @note `MGLMultiPolyline`, `MGLMultiPolygon`, and `MGLShapeCollection` objects + cannot be added to the map view at this time. Any multipolyline, + multipolygon, or shape collection objects that are passed in are silently + ignored. + @param annotations An array of annotation objects. Each object in the array must conform to the `MGLAnnotation` protocol. The map view retains each individual annotation object. @@ -687,6 +698,132 @@ IB_DESIGNABLE */ - (void)removeOverlays:(NS_ARRAY_OF(id ) *)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 ) *)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 + tile sources. + 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 + Mapbox Streets source, + 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 + Mapbox Studio. + + @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 ) *)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 ) *)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 + tile sources. + 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 + Mapbox Streets source, + 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 + Mapbox Studio. + + @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 ) *)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 5b85ff7ec23..c398a9424b6 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" @@ -1614,8 +1615,16 @@ - (void)addAnnotations:(NS_ARRAY_OF(id ) *)annotations { if ([annotation isKindOfClass:[MGLMultiPoint class]]) { // The multipoint knows how to style itself (with the map view’s help). - [(MGLMultiPoint *)annotation addShapeAnnotationObjectToCollection:shapes withDelegate:self]; + MGLMultiPoint *multiPoint = (MGLMultiPoint *)annotation; + if (!multiPoint.pointCount) { + continue; + } + shapes.emplace_back(multiPoint.annotationSegments, [multiPoint shapeAnnotationPropertiesObjectWithDelegate:self]); [userShapes addObject:annotation]; + } else if ([annotation isKindOfClass:[MGLMultiPolyline class]] + || [annotation isKindOfClass:[MGLMultiPolygon class]] + || [annotation isKindOfClass:[MGLShapeCollection class]]) { + continue; } else { MGLAnnotationImage *annotationImage = nil; if (delegateHasImagesForAnnotations) { @@ -2246,6 +2255,55 @@ - (void)resetCursorRects { } } +#pragma mark Data + +- (NS_ARRAY_OF(id ) *)visibleFeaturesAtPoint:(NSPoint)point { + return [self visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:nil]; +} + +- (NS_ARRAY_OF(id ) *)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> optionalLayerIDs; + if (styleLayerIdentifiers) { + __block std::vector layerIDs; + layerIDs.reserve(styleLayerIdentifiers.count); + [styleLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop) { + layerIDs.push_back(identifier.UTF8String); + }]; + optionalLayerIDs = layerIDs; + } + + std::vector features = _mbglMap->queryRenderedFeatures(screenCoordinate, optionalLayerIDs); + return MGLFeaturesFromMBGLFeatures(features); +} + +- (NS_ARRAY_OF(id ) *)visibleFeaturesInRect:(NSRect)rect { + return [self visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:nil]; +} + +- (NS_ARRAY_OF(id ) *)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> optionalLayerIDs; + if (styleLayerIdentifiers) { + __block std::vector layerIDs; + layerIDs.reserve(styleLayerIdentifiers.count); + [styleLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop) { + layerIDs.push_back(identifier.UTF8String); + }]; + optionalLayerIDs = layerIDs; + } + + std::vector 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 a98aea9bcf2..e4545e04bcc 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" diff --git a/src/mbgl/annotation/shape_annotation_impl.cpp b/src/mbgl/annotation/shape_annotation_impl.cpp index 3afc6044d7f..29dd4ef957c 100644 --- a/src/mbgl/annotation/shape_annotation_impl.cpp +++ b/src/mbgl/annotation/shape_annotation_impl.cpp @@ -88,21 +88,22 @@ void ShapeAnnotationImpl::updateTile(const CanonicalTileID& tileID, AnnotationTi const double tolerance = baseTolerance / (maxAmountOfTiles * util::EXTENT); geojsonvt::ProjectedRings rings; - std::vector points; + for (auto& segment : shape.segments) { + std::vector points; + for (auto& latLng : segment) { + const double constrainedLatitude = util::clamp(latLng.latitude, -util::LATITUDE_MAX, util::LATITUDE_MAX); + points.push_back(geojsonvt::LonLat(latLng.longitude, constrainedLatitude)); + } - for (size_t i = 0; i < shape.segments[0].size(); ++i) { // first segment for now (no holes) - const double constrainedLatitude = util::clamp(shape.segments[0][i].latitude, -util::LATITUDE_MAX, util::LATITUDE_MAX); - points.push_back(geojsonvt::LonLat(shape.segments[0][i].longitude, constrainedLatitude)); - } + if (type == geojsonvt::ProjectedFeatureType::Polygon && + (points.front().lon != points.back().lon || points.front().lat != points.back().lat)) { + points.push_back(geojsonvt::LonLat(points.front().lon, points.front().lat)); + } - if (type == geojsonvt::ProjectedFeatureType::Polygon && - (points.front().lon != points.back().lon || points.front().lat != points.back().lat)) { - points.push_back(geojsonvt::LonLat(points.front().lon, points.front().lat)); + auto ring = geojsonvt::Convert::projectRing(points, tolerance); + rings.push_back(ring); } - auto ring = geojsonvt::Convert::projectRing(points, tolerance); - rings.push_back(ring); - std::vector features; features.push_back(geojsonvt::Convert::create(geojsonvt::Tags(), type, rings));