summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMinh Nguyễn <mxn@1ec5.org>2016-05-25 14:35:38 -0700
committerMinh Nguyễn <mxn@1ec5.org>2016-05-27 21:42:38 -0700
commitde905ab64c34e0fd8e35603c4f4fc338d76f89b2 (patch)
tree1f7715b39159cb970d27fe852dc2a5c6f3ae8235
parent4ab98387f1fda80b7bf9328d5aee77f37363d068 (diff)
downloadqtlocation-mapboxgl-de905ab64c34e0fd8e35603c4f4fc338d76f89b2.tar.gz
[ios, osx] Holes in polygons
MGLPolygon (and by extension MGLMultiPolygon) now supports interior rings. The data is preserved in feature querying results, and interior rings are respected when adding polygon overlays to the map. Fixes #1729. [ios, osx] Updated changelog
-rw-r--r--platform/darwin/src/MGLFeature.mm54
-rw-r--r--platform/darwin/src/MGLMultiPoint.h5
-rw-r--r--platform/darwin/src/MGLMultiPoint.mm25
-rw-r--r--platform/darwin/src/MGLMultiPoint_Private.h4
-rw-r--r--platform/darwin/src/MGLPolygon.h28
-rw-r--r--platform/darwin/src/MGLPolygon.mm28
-rw-r--r--platform/darwin/test/MGLFeatureTests.mm38
-rw-r--r--platform/ios/CHANGELOG.md3
-rw-r--r--platform/ios/app/MBXViewController.m16
-rw-r--r--platform/ios/src/MGLMapView.mm7
-rw-r--r--platform/osx/CHANGELOG.md3
-rw-r--r--platform/osx/src/MGLMapView.mm6
-rw-r--r--src/mbgl/annotation/shape_annotation_impl.cpp23
13 files changed, 179 insertions, 61 deletions
diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm
index 3e60b2061b..066d3609a9 100644
--- a/platform/darwin/src/MGLFeature.mm
+++ b/platform/darwin/src/MGLFeature.mm
@@ -171,33 +171,44 @@ class GeometryEvaluator {
public:
MGLShape <MGLFeaturePrivate> * operator()(const mapbox::geometry::point<T> &geometry) const {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
- feature.coordinate = coordinateFromPoint(geometry);
+ feature.coordinate = coordinateFromPointGeometry(geometry);
return feature;
}
MGLShape <MGLFeaturePrivate> * operator()(const mapbox::geometry::line_string<T> &geometry) const {
std::vector<CLLocationCoordinate2D> coordinates;
coordinates.reserve(geometry.size());
- std::transform(geometry.begin(), geometry.end(), std::back_inserter(coordinates), coordinateFromPoint);
+ std::transform(geometry.begin(), geometry.end(), std::back_inserter(coordinates), coordinateFromPointGeometry);
- return [[MGLPolylineFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()];
+ return [MGLPolylineFeature polylineWithCoordinates:&coordinates[0] count:coordinates.size()];
}
MGLShape <MGLFeaturePrivate> * operator()(const mapbox::geometry::polygon<T> &geometry) const {
- // TODO: MGLPolygon doesn’t support holes, so what to do?
- auto &linearRing = geometry.front();
-
+ auto &outerRing = geometry.front();
std::vector<CLLocationCoordinate2D> coordinates;
- coordinates.reserve(linearRing.size());
- std::transform(linearRing.begin(), linearRing.end(), std::back_inserter(coordinates), coordinateFromPoint);
+ coordinates.reserve(outerRing.size());
+ std::transform(outerRing.begin(), outerRing.end(), std::back_inserter(coordinates), coordinateFromPointGeometry);
+
+ 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<CLLocationCoordinate2D> coordinates;
+ coordinates.reserve(innerRing.size());
+ std::transform(innerRing.begin(), innerRing.end(), std::back_inserter(coordinates), coordinateFromPointGeometry);
+ MGLPolygon *innerPolygon = [MGLPolygon polygonWithCoordinates:&coordinates[0] count:coordinates.size()];
+ [innerPolygons addObject:innerPolygon];
+ }
+ }
- return [[MGLPolygonFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()];
+ return [MGLPolygonFeature polygonWithCoordinates:&coordinates[0] count:coordinates.size() interiorPolygons:innerPolygons];
}
MGLShape <MGLFeaturePrivate> * operator()(const mapbox::geometry::multi_point<T> &geometry) const {
std::vector<CLLocationCoordinate2D> coordinates;
coordinates.reserve(geometry.size());
- std::transform(geometry.begin(), geometry.end(), std::back_inserter(coordinates), coordinateFromPoint);
+ std::transform(geometry.begin(), geometry.end(), std::back_inserter(coordinates), coordinateFromPointGeometry);
return [[MGLMultiPointFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()];
}
@@ -207,7 +218,7 @@ public:
for (auto &lineString : geometry) {
std::vector<CLLocationCoordinate2D> coordinates;
coordinates.reserve(lineString.size());
- std::transform(lineString.begin(), lineString.end(), std::back_inserter(coordinates), coordinateFromPoint);
+ std::transform(lineString.begin(), lineString.end(), std::back_inserter(coordinates), coordinateFromPointGeometry);
MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:&coordinates[0] count:coordinates.size()];
[polylines addObject:polyline];
@@ -219,14 +230,25 @@ public:
MGLShape <MGLFeaturePrivate> * operator()(const mapbox::geometry::multi_polygon<T> &geometry) const {
NSMutableArray *polygons = [NSMutableArray arrayWithCapacity:geometry.size()];
for (auto &polygon : geometry) {
- // TODO: MGLPolygon doesn’t support holes, so what to do?
auto &linearRing = polygon.front();
-
std::vector<CLLocationCoordinate2D> coordinates;
coordinates.reserve(linearRing.size());
- std::transform(linearRing.begin(), linearRing.end(), std::back_inserter(coordinates), coordinateFromPoint);
+ std::transform(linearRing.begin(), linearRing.end(), std::back_inserter(coordinates), coordinateFromPointGeometry);
+
+ NSMutableArray *innerPolygons;
+ if (polygon.size() > 1) {
+ innerPolygons = [NSMutableArray arrayWithCapacity:polygon.size() - 1];
+ for (auto iter = polygon.begin() + 1; iter != polygon.end(); iter++) {
+ auto &innerRing = *iter;
+ std::vector<CLLocationCoordinate2D> coordinates;
+ coordinates.reserve(innerRing.size());
+ std::transform(innerRing.begin(), innerRing.end(), std::back_inserter(coordinates), coordinateFromPointGeometry);
+ MGLPolygon *innerPolygon = [MGLPolygon polygonWithCoordinates:&coordinates[0] count:coordinates.size()];
+ [innerPolygons addObject:innerPolygon];
+ }
+ }
- MGLPolygon *polygonObject = [MGLPolygon polygonWithCoordinates:&coordinates[0] count:coordinates.size()];
+ MGLPolygon *polygonObject = [MGLPolygon polygonWithCoordinates:&coordinates[0] count:coordinates.size() interiorPolygons:innerPolygons];
[polygons addObject:polygonObject];
}
@@ -245,7 +267,7 @@ public:
}
private:
- static CLLocationCoordinate2D coordinateFromPoint(const mapbox::geometry::point<T> &point) {
+ static CLLocationCoordinate2D coordinateFromPointGeometry(const mapbox::geometry::point<T> &point) {
return CLLocationCoordinate2DMake(point.y, point.x);
}
};
diff --git a/platform/darwin/src/MGLMultiPoint.h b/platform/darwin/src/MGLMultiPoint.h
index 041c52e8f2..2d6b327086 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 a864b7bce7..aaf8447274 100644
--- a/platform/darwin/src/MGLMultiPoint.mm
+++ b/platform/darwin/src/MGLMultiPoint.mm
@@ -14,7 +14,6 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) {
@implementation MGLMultiPoint
{
- CLLocationCoordinate2D *_coords;
size_t _count;
MGLCoordinateBounds _bounds;
}
@@ -27,13 +26,13 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) {
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 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) {
- (void)dealloc
{
- free(_coords);
+ free(_coordinates);
}
- (CLLocationCoordinate2D)coordinate
@@ -59,7 +58,7 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) {
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 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) {
for (NSUInteger i = range.location; i < range.location + range.length; i++)
{
- coords[index] = _coords[i];
+ coords[index] = _coordinates[i];
index++;
}
}
@@ -104,24 +103,16 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) {
return MGLLatLngBoundsFromCoordinateBounds(_bounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds));
}
-- (void)addShapeAnnotationObjectToCollection:(std::vector<mbgl::ShapeAnnotation> &)shapes withDelegate:(id <MGLMultiPointDelegate>)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 <MGLMultiPointDelegate>)delegate {
diff --git a/platform/darwin/src/MGLMultiPoint_Private.h b/platform/darwin/src/MGLMultiPoint_Private.h
index c1f1fa1584..2c1e0b7222 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<mbgl::ShapeAnnotation> &)shapes withDelegate:(id <MGLMultiPointDelegate>)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 <MGLMultiPointDelegate>)delegate;
diff --git a/platform/darwin/src/MGLPolygon.h b/platform/darwin/src/MGLPolygon.h
index a12e62b106..e1dc553f30 100644
--- a/platform/darwin/src/MGLPolygon.h
+++ b/platform/darwin/src/MGLPolygon.h
@@ -17,6 +17,17 @@ NS_ASSUME_NONNULL_BEGIN
@interface MGLPolygon : MGLMultiPoint <MGLOverlay>
/**
+ 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,21 @@ 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
diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm
index 6febf6d81b..5a24cb0791 100644
--- a/platform/darwin/src/MGLPolygon.mm
+++ b/platform/darwin/src/MGLPolygon.mm
@@ -7,10 +7,30 @@
@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<MGLPolygon *> *)interiorPolygons {
+ return [[self alloc] initWithCoordinates:coords count:count interiorPolygons:interiorPolygons];
+}
+
+- (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count interiorPolygons:(NSArray<MGLPolygon *> *)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 <MGLMultiPointDelegate>)delegate {
diff --git a/platform/darwin/test/MGLFeatureTests.mm b/platform/darwin/test/MGLFeatureTests.mm
index d9334c76af..6cf038d4fb 100644
--- a/platform/darwin/test/MGLFeatureTests.mm
+++ b/platform/darwin/test/MGLFeatureTests.mm
@@ -23,10 +23,16 @@
mapbox::geometry::polygon<double> polygon = {
{
- { -77.0325453144239, 38.9131982 },
- { -122.4135302, 37.7757368 },
- { 77.6368034, 12.9810816 },
- { -74.2178961777998, -13.15589555 },
+ { 1, 1 },
+ { 4, 1 },
+ { 4, 4 },
+ { 1, 4 },
+ },
+ {
+ { 2, 2 },
+ { 3, 2 },
+ { 3, 3 },
+ { 2, 3 },
},
};
features.emplace_back(polygon);
@@ -52,6 +58,30 @@
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 {
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index 0754aa2a0d..65b8eb74b4 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -10,7 +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. ([#5110](https://github.com/mapbox/mapbox-gl-native/pull/5110))
+- 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 2f5aacfe6c..c72bdfd0f8 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -306,6 +306,22 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
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)
{
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index 44a3cbc4c8..d81c588cd6 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -2812,7 +2812,12 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
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]])
diff --git a/platform/osx/CHANGELOG.md b/platform/osx/CHANGELOG.md
index 0e4da04545..f2e1be966f 100644
--- a/platform/osx/CHANGELOG.md
+++ b/platform/osx/CHANGELOG.md
@@ -3,7 +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. ([#5110](https://github.com/mapbox/mapbox-gl-native/pull/5110))
+* 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/src/MGLMapView.mm b/platform/osx/src/MGLMapView.mm
index 20e59505b4..660c5d9ee0 100644
--- a/platform/osx/src/MGLMapView.mm
+++ b/platform/osx/src/MGLMapView.mm
@@ -1615,7 +1615,11 @@ public:
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]]) {
// TODO: Add real support for these types down in mbgl instead of breaking the annotation apart.
diff --git a/src/mbgl/annotation/shape_annotation_impl.cpp b/src/mbgl/annotation/shape_annotation_impl.cpp
index 3afc6044d7..29dd4ef957 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<geojsonvt::LonLat> points;
+ for (auto& segment : shape.segments) {
+ std::vector<geojsonvt::LonLat> 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<geojsonvt::ProjectedFeature> features;
features.push_back(geojsonvt::Convert::create(geojsonvt::Tags(), type, rings));