Skip to content
This repository was archived by the owner on Aug 8, 2023. It is now read-only.

Commit 1216050

Browse files
authored
Add MGLPointCollection for GeoJSON multipoints (#6742)
* [ios, macos] Introduce MGLPointCollection This makes MGLMultiPoint abstract again so that it is only a place for shared functionality of polygons and polylines. The multipoint feature replaces the point collection feature and can be used to initialize a MGLGeoJSONSource. The previously added swift_names for polyline and polygon are removed, for now. This also updates the iOS and macOS annotation adding logic so that unwanted shapes really are avoided. Previously the combined OR conditions meant that an annotation had to logically be NOT a kind of all three types so the check always let the annotation slip through. This also expands the guard to deflect the new MGLPointCollection.
1 parent baf82fc commit 1216050

23 files changed

+302
-151
lines changed

platform/darwin/src/MGLFeature.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#import "MGLPolyline.h"
44
#import "MGLPolygon.h"
55
#import "MGLPointAnnotation.h"
6+
#import "MGLPointCollection.h"
67
#import "MGLShapeCollection.h"
78

89
NS_ASSUME_NONNULL_BEGIN
@@ -134,10 +135,10 @@ NS_ASSUME_NONNULL_BEGIN
134135
@end
135136

136137
/**
137-
The `MGLMultiPointFeature` class represents a multipoint in a
138+
The `MGLPointCollectionFeature` class represents a multipoint in a
138139
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
139140
*/
140-
@interface MGLMultiPointFeature : MGLMultiPoint <MGLFeature>
141+
@interface MGLPointCollectionFeature : MGLPointCollection <MGLFeature>
141142
@end
142143

143144
/**

platform/darwin/src/MGLFeature.mm

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#import "MGLValueEvaluator.h"
77

88
#import "MGLShape_Private.h"
9-
#import "MGLMultiPoint_Private.h"
9+
#import "MGLPointCollection_Private.h"
1010
#import "MGLPolyline+MGLAdditions.h"
1111
#import "MGLPolygon+MGLAdditions.h"
1212
#import "NSDictionary+MGLAdditions.h"
@@ -82,10 +82,10 @@ - (NSDictionary *)geoJSONDictionary {
8282

8383
@end
8484

85-
@interface MGLMultiPointFeature () <MGLFeaturePrivate>
85+
@interface MGLPointCollectionFeature () <MGLFeaturePrivate>
8686
@end
8787

88-
@implementation MGLMultiPointFeature
88+
@implementation MGLPointCollectionFeature
8989

9090
@synthesize identifier;
9191
@synthesize attributes;
@@ -202,7 +202,7 @@ - (NSDictionary *)geoJSONDictionary {
202202

203203
MGLShape <MGLFeaturePrivate> * operator()(const mbgl::MultiPoint<T> &geometry) const {
204204
std::vector<CLLocationCoordinate2D> coordinates = toLocationCoordinates2D(geometry);
205-
return [[MGLMultiPointFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()];
205+
return [[MGLPointCollectionFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()];
206206
}
207207

208208
MGLShape <MGLFeaturePrivate> * operator()(const mbgl::MultiLineString<T> &geometry) const {

platform/darwin/src/MGLMultiPoint.h

+6-15
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,15 @@
66
NS_ASSUME_NONNULL_BEGIN
77

88
/**
9-
The `MGLMultiPoint` class is used to define shapes composed of multiple points.
10-
This class is also the superclass of `MGLPolyline` and `MGLPolygon`. The
11-
methods and properties of this class can be used to access information about
12-
the specific points associated with a line or polygon.
9+
The `MGLMultiPoint` class is an abstract superclass used to define shapes
10+
composed of multiple points. You should not create instances of this class
11+
directly. Instead, you should create instances of the `MGLPolyline` or
12+
`MGLPolygon` classes. However, you can use the method and properties of this
13+
class to access information about the specific points associated with the line
14+
or polygon.
1315
*/
1416
@interface MGLMultiPoint : MGLShape
1517

16-
/**
17-
Creates and returns an `MGLMultiPoint` object from the specified set of
18-
coordinates.
19-
20-
@param coords The array of coordinates defining the shape. The data in this
21-
array is copied to the new object.
22-
@param count The number of items in the `coords` array.
23-
@return A new multipoint object.
24-
*/
25-
+ (instancetype)multiPointWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count NS_SWIFT_NAME(multiPoint(coordinates:count:));
26-
2718
/**
2819
The array of coordinates associated with the shape.
2920

platform/darwin/src/MGLMultiPoint.mm

-28
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ @implementation MGLMultiPoint
1818
MGLCoordinateBounds _bounds;
1919
}
2020

21-
+ (instancetype)multiPointWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count
22-
{
23-
return [[self alloc] initWithCoordinates:coords count:count];
24-
}
25-
2621
- (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count
2722
{
2823
self = [super init];
@@ -146,29 +141,6 @@ - (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds
146141
return mbgl::SymbolAnnotation({mbgl::Point<double>()});
147142
}
148143

149-
- (mbgl::Feature)featureObject
150-
{
151-
mbgl::MultiPoint<double> multiPoint;
152-
multiPoint.reserve(self.pointCount);
153-
for (NSInteger i = 0; i< self.pointCount; i++)
154-
{
155-
multiPoint.push_back(mbgl::Point<double>(self.coordinates[i].longitude, self.coordinates[i].latitude));
156-
}
157-
return mbgl::Feature {multiPoint};
158-
}
159-
160-
- (NSDictionary *)geoJSONDictionary
161-
{
162-
NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:self.pointCount];
163-
for (NSUInteger index = 0; index < self.pointCount; index++) {
164-
CLLocationCoordinate2D coordinate = self.coordinates[index];
165-
[coordinates addObject:@[@(coordinate.longitude), @(coordinate.latitude)]];
166-
}
167-
168-
return @{@"type": @"MultiPoint",
169-
@"coordinates": coordinates};
170-
}
171-
172144
- (NSString *)description
173145
{
174146
return [NSString stringWithFormat:@"<%@: %p; count = %lu; bounds = %@>",
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#import <Foundation/Foundation.h>
2+
#import <CoreLocation/CoreLocation.h>
3+
4+
#import "MGLOverlay.h"
5+
#import "MGLShape.h"
6+
7+
/**
8+
The `MGLPointCollection` class is used to define an array of disconnected
9+
coordinates. The points in the collection may be related but are not
10+
connected visually in any way.
11+
12+
@note `MGLPointCollection` objects cannot be added to a map view using
13+
`-[MGLMapView addAnnotations:]` and related methods. However, when used in a
14+
`MGLPointCollectionFeature` to initialize a `MGLGeoJSONSource` that is added
15+
to the map view's style, the point collection represents as a group of distinct
16+
annotations.
17+
*/
18+
@interface MGLPointCollection : MGLShape <MGLOverlay>
19+
20+
/**
21+
Creates and returns a `MGLPointCollection` object from the specified set of
22+
coordinates.
23+
24+
@param coords The array of coordinates defining the shape. The data in this
25+
array is copied to the new object.
26+
@param count The number of items in the `coords` array.
27+
@return A new point collection object.
28+
*/
29+
+ (instancetype)pointCollectionWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count;
30+
31+
/** The array of coordinates associated with the shape. */
32+
@property (nonatomic, readonly) CLLocationCoordinate2D *coordinates NS_RETURNS_INNER_POINTER;
33+
34+
/** The number of coordinates associated with the shape. */
35+
@property (nonatomic, readonly) NSUInteger pointCount;
36+
37+
/**
38+
Retrieves one or more coordinates associated with the shape.
39+
40+
@param coords On input, you must provide a C array of structures large enough
41+
to hold the desired number of coordinates. On output, this structure
42+
contains the requested coordinate data.
43+
@param range The range of points you want. The `location` field indicates the
44+
first point you are requesting, with `0` being the first point, `1` being
45+
the second point, and so on. The `length` field indicates the number of
46+
points you want. The array in _`coords`_ must be large enough to accommodate
47+
the number of requested coordinates.
48+
*/
49+
- (void)getCoordinates:(CLLocationCoordinate2D *)coords range:(NSRange)range;
50+
51+
@end
+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#import "MGLPointCollection_Private.h"
2+
#import "MGLGeometry_Private.h"
3+
4+
#import <mbgl/util/geometry.hpp>
5+
#import <mbgl/util/feature.hpp>
6+
7+
NS_ASSUME_NONNULL_BEGIN
8+
9+
@implementation MGLPointCollection
10+
{
11+
size_t _count;
12+
MGLCoordinateBounds _bounds;
13+
}
14+
15+
+ (instancetype)pointCollectionWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count
16+
{
17+
return [[self alloc] initWithCoordinates:coords count:count];
18+
}
19+
20+
- (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count
21+
{
22+
self = [super init];
23+
if (self)
24+
{
25+
_count = count;
26+
_coordinates = (CLLocationCoordinate2D *)malloc(_count * sizeof(CLLocationCoordinate2D));
27+
28+
mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
29+
30+
for (NSUInteger i = 0; i < count; i++)
31+
{
32+
_coordinates[i] = coords[i];
33+
bounds.extend(mbgl::LatLng(coords[i].latitude, coords[i].longitude));
34+
}
35+
36+
_bounds = MGLCoordinateBoundsFromLatLngBounds(bounds);
37+
}
38+
return self;
39+
}
40+
41+
- (NSUInteger)pointCount
42+
{
43+
return _count;
44+
}
45+
46+
- (CLLocationCoordinate2D)coordinate
47+
{
48+
assert(_count > 0);
49+
50+
return CLLocationCoordinate2DMake(_coordinates[0].latitude, _coordinates[0].longitude);
51+
}
52+
53+
- (void)getCoordinates:(CLLocationCoordinate2D *)coords range:(NSRange)range
54+
{
55+
if (range.location + range.length > _count)
56+
{
57+
[NSException raise:NSRangeException
58+
format:@"Invalid coordinate range %@ extends beyond current coordinate count of %zu",
59+
NSStringFromRange(range), _count];
60+
}
61+
62+
NSUInteger index = 0;
63+
64+
for (NSUInteger i = range.location; i < range.location + range.length; i++)
65+
{
66+
coords[index] = _coordinates[i];
67+
index++;
68+
}
69+
}
70+
71+
- (MGLCoordinateBounds)overlayBounds
72+
{
73+
return _bounds;
74+
}
75+
76+
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds
77+
{
78+
return MGLLatLngBoundsFromCoordinateBounds(_bounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds));
79+
}
80+
81+
- (mbgl::Feature)featureObject
82+
{
83+
mbgl::MultiPoint<double> multiPoint;
84+
multiPoint.reserve(self.pointCount);
85+
for (NSInteger i = 0; i< self.pointCount; i++)
86+
{
87+
multiPoint.push_back(mbgl::Point<double>(self.coordinates[i].longitude, self.coordinates[i].latitude));
88+
}
89+
return mbgl::Feature {multiPoint};
90+
}
91+
92+
- (NSDictionary *)geoJSONDictionary
93+
{
94+
NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:self.pointCount];
95+
for (NSUInteger index = 0; index < self.pointCount; index++) {
96+
CLLocationCoordinate2D coordinate = self.coordinates[index];
97+
[coordinates addObject:@[@(coordinate.longitude), @(coordinate.latitude)]];
98+
}
99+
100+
return @{@"type": @"MultiPoint",
101+
@"coordinates": coordinates};
102+
}
103+
104+
- (NSString *)description
105+
{
106+
return [NSString stringWithFormat:@"<%@: %p; count = %lu>",
107+
NSStringFromClass([self class]), (void *)self, (unsigned long)_count];
108+
}
109+
110+
@end
111+
112+
NS_ASSUME_NONNULL_END
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#import "MGLPointCollection.h"
2+
3+
NS_ASSUME_NONNULL_BEGIN
4+
5+
@interface MGLPointCollection (Private)
6+
7+
- (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count;
8+
9+
@end
10+
11+
NS_ASSUME_NONNULL_END

platform/darwin/src/MGLPolygon.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ NS_ASSUME_NONNULL_BEGIN
3636
@param count The number of items in the `coords` array.
3737
@return A new polygon object.
3838
*/
39-
+ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count NS_SWIFT_NAME(polygon(coordinates:count:));
39+
+ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count;
4040

4141
/**
4242
Creates and returns an `MGLPolygon` object from the specified set of

platform/darwin/src/MGLPolyline.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN
2525
@param count The number of items in the `coords` array.
2626
@return A new polyline object.
2727
*/
28-
+ (instancetype)polylineWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count NS_SWIFT_NAME(polyline(coordinates:count:));
28+
+ (instancetype)polylineWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count;
2929

3030
@end
3131

platform/darwin/test/MGLFeatureTests.mm

+19-18
Original file line numberDiff line numberDiff line change
@@ -227,24 +227,6 @@ - (void)testPolygonFeatureGeoJSONDictionary {
227227
XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry);
228228
}
229229

230-
- (void)testMultiPointFeatureGeoJSONDictionary {
231-
CLLocationCoordinate2D coord1 = { 0, 0 };
232-
CLLocationCoordinate2D coord2 = { 10, 10 };
233-
CLLocationCoordinate2D coord3 = { 0, 0 };
234-
CLLocationCoordinate2D coords[] = { coord1, coord2, coord3 };
235-
MGLMultiPointFeature *multiPointFeature = [MGLMultiPointFeature multiPointWithCoordinates:coords count:3];
236-
237-
// A GeoJSON feature
238-
NSDictionary *geoJSONFeature = [multiPointFeature geoJSONDictionary];
239-
240-
// it has the correct geometry
241-
NSDictionary *expectedGeometry = @{@"type": @"MultiPoint",
242-
@"coordinates": @[@[@(coord1.longitude), @(coord1.latitude)],
243-
@[@(coord2.longitude), @(coord2.latitude)],
244-
@[@(coord3.longitude), @(coord3.latitude)]]};
245-
XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry);
246-
}
247-
248230
- (void)testMultiPolylineFeatureGeoJSONDictionary {
249231
CLLocationCoordinate2D coord1 = { 0, 0 };
250232
CLLocationCoordinate2D coord2 = { 10, 10 };
@@ -296,6 +278,25 @@ - (void)testMultiPolygonFeatureGeoJSONDictionary {
296278
XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry);
297279
}
298280

281+
- (void)testPointCollectionFeatureGeoJSONDictionary {
282+
CLLocationCoordinate2D coord1 = { 0, 0 };
283+
CLLocationCoordinate2D coord2 = { 10, 10 };
284+
CLLocationCoordinate2D coord3 = { 0, 0 };
285+
CLLocationCoordinate2D coords[] = { coord1, coord2, coord3 };
286+
MGLPointCollectionFeature *pointCollectionFeature = [MGLPointCollectionFeature pointCollectionWithCoordinates:coords count:3];
287+
288+
// A GeoJSON feature
289+
NSDictionary *geoJSONFeature = [pointCollectionFeature geoJSONDictionary];
290+
291+
// it has the correct geometry
292+
NSDictionary *expectedGeometry = @{@"type": @"MultiPoint",
293+
@"coordinates": @[@[@(coord1.longitude), @(coord1.latitude)],
294+
@[@(coord2.longitude), @(coord2.latitude)],
295+
@[@(coord3.longitude), @(coord3.latitude)]]};
296+
XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry);
297+
298+
}
299+
299300
- (void)testShapeCollectionFeatureGeoJSONDictionary {
300301
MGLPointAnnotation *pointFeature = [[MGLPointAnnotation alloc] init];
301302
CLLocationCoordinate2D pointCoordinate = { 10, 10 };

platform/ios/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
3232
* Improved style parsing performance. ([#6170](https://github.com/mapbox/mapbox-gl-native/pull/6170))
3333
* Improved feature querying performance. ([#6514](https://github.com/mapbox/mapbox-gl-native/pull/6514))
3434
* A feature's `identifier` and `attributes` properties can now be mutated. ([#6728](https://github.com/mapbox/mapbox-gl-native/pull/6728))
35+
* Fixed an issue causing abstract `MGLMultiPointFeature` objects to be returned in feature query results. Now concrete `MGLPointCollectionFeature` objects are returned. ([#6742](https://github.com/mapbox/mapbox-gl-native/pull/6742))
36+
* Fixed an issue where shapes that cannot currently be visually represented as annotations were still shown on the map as point annotations. ([#6764](https://github.com/mapbox/mapbox-gl-native/issues/6764))
3537

3638
### User location
3739

0 commit comments

Comments
 (0)