summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Bounds <jesse@rebounds.net>2017-01-11 16:05:38 -0800
committerGitHub <noreply@github.com>2017-01-11 16:05:38 -0800
commit6ad47cfbad038ee8330fece5da7438d084e67a68 (patch)
tree98aa48e9c2562791a310c30e5d107c4221f99c1e
parent4332b3b9539e1c059b18c77ef6c0a9e6af44fe84 (diff)
downloadqtlocation-mapboxgl-6ad47cfbad038ee8330fece5da7438d084e67a68.tar.gz
[ios, macos] Add convenience initializers to shape source (#7665)
This adds two new convenience initializers to MGLShapeSource: -initWithIdentifier:features:options: takes an array of shape objects that conform to MGLFeature, inserts them in a shape collection feature and creates a source with that shape. -initWithIdentifier:shapes:options does the same but with concrete MGLShape objects that get added to a shape collection. Throw an exception if an shape source is created with the features initializer but is sent an array of features that contains something that is not actually an object that conforms to the feature protocol. Updates to geojson data guide Qualify APIs that take arrays of shapes that are features
-rw-r--r--platform/darwin/docs/guides/Working with GeoJSON Data.md10
-rw-r--r--platform/darwin/src/MGLFeature.mm2
-rw-r--r--platform/darwin/src/MGLShapeSource.h46
-rw-r--r--platform/darwin/src/MGLShapeSource.mm15
-rw-r--r--platform/darwin/test/MGLDocumentationExampleTests.swift3
-rw-r--r--platform/darwin/test/MGLShapeSourceTests.mm39
-rw-r--r--platform/ios/app/MBXViewController.m3
7 files changed, 110 insertions, 8 deletions
diff --git a/platform/darwin/docs/guides/Working with GeoJSON Data.md b/platform/darwin/docs/guides/Working with GeoJSON Data.md
index 0fffed06dd..adaf053e41 100644
--- a/platform/darwin/docs/guides/Working with GeoJSON Data.md
+++ b/platform/darwin/docs/guides/Working with GeoJSON Data.md
@@ -36,6 +36,16 @@ resulting shape or feature object into the
the map, or you can use the object and its properties to power non-map-related
functionality in your application.
+To include multiple shapes in the source, create and pass an `MGLShapeCollection` or
+ `MGLShapeCollectionFeature` object to
+ `-[MGLShapeSource initWithIdentifier:shape:options:]`. Alternatively, use the
+ `-[MGLShapeSource initWithIdentifier:features:options:]` or
+ `-[MGLShapeSource initWithIdentifier:shapes:options:]` method to create a shape source
+ with an array. `-[MGLShapeSource initWithIdentifier:features:options:]` accepts only `MGLFeature`
+ instances, such as `MGLPointFeature` objects, whose attributes you can use when
+ applying a predicate to `MGLVectorStyleLayer` or configuring a style layer’s
+ appearance.
+
## Extracting GeoJSON data from the map
Any `MGLShape`, `MGLFeature`, or `MGLShapeCollectionFeature` object has an
diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm
index 5b63beae87..3bd7eae535 100644
--- a/platform/darwin/src/MGLFeature.mm
+++ b/platform/darwin/src/MGLFeature.mm
@@ -184,7 +184,7 @@ MGL_DEFINE_FEATURE_IS_EQUAL();
@dynamic shapes;
-+ (instancetype)shapeCollectionWithShapes:(NSArray *)shapes {
++ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)shapes {
return [super shapeCollectionWithShapes:shapes];
}
diff --git a/platform/darwin/src/MGLShapeSource.h b/platform/darwin/src/MGLShapeSource.h
index 8c8a2ab4e5..7d8a645959 100644
--- a/platform/darwin/src/MGLShapeSource.h
+++ b/platform/darwin/src/MGLShapeSource.h
@@ -103,8 +103,7 @@ extern const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance;
CLLocationCoordinate2D(latitude: 38.91, longitude: -77.04),
]
let polyline = MGLPolylineFeature(coordinates: &coordinates, count: UInt(coordinates.count))
- let shape = MGLShapeCollectionFeature(shapes: [polyline])
- let source = MGLShapeSource(identifier: "lines", shape: shape, options: nil)
+ let source = MGLShapeSource(identifier: "lines", features: [polyline], options: nil)
mapView.style?.addSource(source)
```
*/
@@ -131,7 +130,9 @@ extern const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance;
To specify attributes about the shape, use an instance of an `MGLShape`
subclass that conforms to the `MGLFeature` protocol, such as `MGLPointFeature`.
To include multiple shapes in the source, use an `MGLShapeCollection` or
- `MGLShapeCollectionFeature` object.
+ `MGLShapeCollectionFeature` object, or use the
+ `-initWithIdentifier:features:options:` or
+ `-initWithIdentifier:shapes:options:` methods.
To create a shape from GeoJSON source code, use the
`+[MGLShape shapeWithData:encoding:error:]` method.
@@ -143,6 +144,45 @@ extern const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance;
*/
- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
+/**
+ Returns a shape source with an identifier, an array of features, and a dictionary
+ of options for the source.
+
+ Unlike `-initWithIdentifier:shapes:options:`, this method accepts `MGLFeature`
+ instances, such as `MGLPointFeature` objects, whose attributes you can use when
+ applying a predicate to `MGLVectorStyleLayer` or configuring a style layer’s
+ appearance.
+
+ To create a shape from GeoJSON source code, use the
+ `+[MGLShape shapeWithData:encoding:error:]` method.
+
+ @param identifier A string that uniquely identifies the source.
+ @param features An array of objects that conform to the MGLFeature protocol.
+ @param options An `NSDictionary` of options for this source.
+ @return An initialized shape source.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier features:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)features options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options;
+
+/**
+ Returns a shape source with an identifier, an array of shapes, and a dictionary of
+ options for the source.
+
+ Any `MGLFeature` instance passed into this initializer is treated as an ordinary
+ shape, causing any attributes to be inaccessible to an `MGLVectorStyleLayer` when
+ evaluating a predicate or configuring certain layout or paint attributes. To
+ preserve the attributes associated with each feature, use the
+ `-initWithIdentifier:features:options:` method instead.
+
+ To create a shape from GeoJSON source code, use the
+ `+[MGLShape shapeWithData:encoding:error:]` method.
+
+ @param identifier A string that uniquely identifies the source.
+ @param shapes An array of shapes; each shape is a member of a concrete subclass of MGLShape.
+ @param options An `NSDictionary` of options for this source.
+ @return An initialized shape source.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NS_ARRAY_OF(MGLShape *) *)shapes options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options;
+
#pragma mark Accessing a Source’s Content
/**
diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm
index 0647236e80..50322f300c 100644
--- a/platform/darwin/src/MGLShapeSource.mm
+++ b/platform/darwin/src/MGLShapeSource.mm
@@ -56,6 +56,21 @@ const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLSh
return self;
}
+- (instancetype)initWithIdentifier:(NSString *)identifier features:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)features options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+ for (id <MGLFeature> feature in features) {
+ if (![feature conformsToProtocol:@protocol(MGLFeature)]) {
+ [NSException raise:NSInvalidArgumentException format:@"The object %@ included in the features argument does not conform to the MGLFeature protocol.", feature];
+ }
+ }
+ MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:features];
+ return [self initWithIdentifier:identifier shape:shapeCollectionFeature options:options];
+}
+
+- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NS_ARRAY_OF(MGLShape *) *)shapes options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+ MGLShapeCollection *shapeCollection = [MGLShapeCollection shapeCollectionWithShapes:shapes];
+ return [self initWithIdentifier:identifier shape:shapeCollection options:options];
+}
+
- (instancetype)initWithRawSource:(mbgl::style::GeoJSONSource *)rawSource {
return [super initWithRawSource:rawSource];
}
diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift
index 5f0e83b2ca..d796b4e708 100644
--- a/platform/darwin/test/MGLDocumentationExampleTests.swift
+++ b/platform/darwin/test/MGLDocumentationExampleTests.swift
@@ -66,8 +66,7 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
CLLocationCoordinate2D(latitude: 38.91, longitude: -77.04),
]
let polyline = MGLPolylineFeature(coordinates: &coordinates, count: UInt(coordinates.count))
- let shape = MGLShapeCollectionFeature(shapes: [polyline])
- let source = MGLShapeSource(identifier: "lines", shape: shape, options: nil)
+ let source = MGLShapeSource(identifier: "lines", features: [polyline], options: nil)
mapView.style?.addSource(source)
//#-end-example-code
diff --git a/platform/darwin/test/MGLShapeSourceTests.mm b/platform/darwin/test/MGLShapeSourceTests.mm
index 2662d4b6f0..cf32b5c821 100644
--- a/platform/darwin/test/MGLShapeSourceTests.mm
+++ b/platform/darwin/test/MGLShapeSourceTests.mm
@@ -278,4 +278,43 @@
XCTAssert(shape.shapes.count == 6, @"Shape collection should contain 6 shapes");
}
+- (void)testMGLShapeSourceWithFeaturesConvenienceInitializer {
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(100.0, 0.0),
+ CLLocationCoordinate2DMake(101.0, 0.0),
+ CLLocationCoordinate2DMake(101.0, 1.0),
+ CLLocationCoordinate2DMake(100.0, 1.0),
+ CLLocationCoordinate2DMake(100.0, 0.0)};
+
+ MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:sizeof(coordinates)/sizeof(coordinates[0]) interiorPolygons:nil];
+
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" features:@[polygonFeature] options:nil];
+ MGLShapeCollectionFeature *shape = (MGLShapeCollectionFeature *)source.shape;
+
+ XCTAssertTrue([shape isKindOfClass:[MGLShapeCollectionFeature class]]);
+ XCTAssertEqual(shape.shapes.count, 1, @"Shape collection should contain 1 shape");
+
+ // when a shape is included in the features array
+ MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:sizeof(coordinates)/sizeof(coordinates[0]) interiorPolygons:nil];
+
+ XCTAssertThrowsSpecificNamed([[MGLShapeSource alloc] initWithIdentifier:@"source-id-invalid" features:@[polygon] options:nil], NSException, NSInvalidArgumentException, @"Shape source should raise an exception if a shape is sent to the features initializer");
+}
+
+- (void)testMGLShapeSourceWithShapesConvenienceInitializer {
+ CLLocationCoordinate2D coordinates[] = {
+ CLLocationCoordinate2DMake(100.0, 0.0),
+ CLLocationCoordinate2DMake(101.0, 0.0),
+ CLLocationCoordinate2DMake(101.0, 1.0),
+ CLLocationCoordinate2DMake(100.0, 1.0),
+ CLLocationCoordinate2DMake(100.0, 0.0)};
+
+ MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:sizeof(coordinates)/sizeof(coordinates[0]) interiorPolygons:nil];
+
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shapes:@[polygon] options:nil];
+ MGLShapeCollectionFeature *shape = (MGLShapeCollectionFeature *)source.shape;
+
+ XCTAssertTrue([shape isKindOfClass:[MGLShapeCollection class]]);
+ XCTAssertEqual(shape.shapes.count, 1, @"Shape collection should contain 1 shape");
+}
+
@end
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index 13401997a0..ff69581dac 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -919,8 +919,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
}
dispatch_async(dispatch_get_main_queue(), ^{
- MGLShapeCollectionFeature *features = [MGLShapeCollectionFeature shapeCollectionWithShapes:visibleFeatures];
- MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:querySourceID shape:features options:nil];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:querySourceID features:visibleFeatures options:nil];
[self.mapView.style addSource:source];
MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:queryLayerID source:source];