From f2ca03005b44d9b90ed3aad49e94216585988f27 Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Tue, 18 Oct 2016 16:43:37 -0400 Subject: [PATCH 01/25] [ios] Fix deploy script temp directory creation (#6740) Also: - Ignore stdout from github-release uploads. - Add execution time to finished message. --- platform/ios/scripts/deploy-packages.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/platform/ios/scripts/deploy-packages.sh b/platform/ios/scripts/deploy-packages.sh index 51b90a545..8ad5e7abb 100755 --- a/platform/ios/scripts/deploy-packages.sh +++ b/platform/ios/scripts/deploy-packages.sh @@ -43,7 +43,7 @@ buildPackageStyle() { github-release upload \ --tag "ios-v${PUBLISH_VERSION}" \ --name ${file_name} \ - --file "${BINARY_DIRECTORY}/${file_name}" + --file "${BINARY_DIRECTORY}/${file_name}" > /dev/null fi } @@ -58,9 +58,6 @@ BINARY_DIRECTORY=${BINARY_DIRECTORY:-build/ios/deploy} GITHUB_RELEASE=${GITHUB_RELEASE:-true} PUBLISH_PRE_FLAG='' -rm -rf ${BINARY_DIRECTORY} -mkdir -p ${BINARY_DIRECTORY} - if [[ ${GITHUB_RELEASE} = "true" ]]; then GITHUB_RELEASE=true # Assign bool, not just a string @@ -98,6 +95,7 @@ git checkout ${VERSION_TAG} step "Deploying version ${PUBLISH_VERSION}…" make clean && make distclean +mkdir -p ${BINARY_DIRECTORY} if [[ "${GITHUB_RELEASE}" == true ]]; then step "Create GitHub release…" @@ -116,4 +114,4 @@ buildPackageStyle "iframework" "symbols-dynamic" buildPackageStyle "iframework SYMBOLS=NO" "dynamic" buildPackageStyle "ifabric" "fabric" -step "Finished deploying ${PUBLISH_VERSION}" +step "Finished deploying ${PUBLISH_VERSION} in $(($SECONDS / 60)) minutes and $(($SECONDS % 60)) seconds" From 0b37408812131c91afd8b3accf1add709f5ca81c Mon Sep 17 00:00:00 2001 From: Jesse Bounds Date: Tue, 18 Oct 2016 14:32:32 -0700 Subject: [PATCH 02/25] [ios] Optimize event uploading (#6737) Upload any events collected when the app was in use for apps that only have "when in use" location permissions. Also, for all apps, avoid posting event data if there is only a single event. --- platform/ios/src/MGLMapboxEvents.m | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/platform/ios/src/MGLMapboxEvents.m b/platform/ios/src/MGLMapboxEvents.m index 15b78b65a..d86114d01 100644 --- a/platform/ios/src/MGLMapboxEvents.m +++ b/platform/ios/src/MGLMapboxEvents.m @@ -129,6 +129,7 @@ const NSTimeInterval MGLFlushInterval = 180; @implementation MGLMapboxEvents { NSString *_instanceID; + UIBackgroundTaskIdentifier _backgroundTaskIdentifier; } + (void)initialize { @@ -257,9 +258,20 @@ const NSTimeInterval MGLFlushInterval = 180; } - (void)pauseOrResumeMetricsCollectionIfRequired { + UIApplication *application = [UIApplication sharedApplication]; + // Prevent blue status bar when host app has `when in use` permission only and it is not in foreground if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse && - [UIApplication sharedApplication].applicationState == UIApplicationStateBackground) { + application.applicationState == UIApplicationStateBackground) { + + if (_backgroundTaskIdentifier == UIBackgroundTaskInvalid) { + _backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{ + [application endBackgroundTask:_backgroundTaskIdentifier]; + _backgroundTaskIdentifier = UIBackgroundTaskInvalid; + }]; + [self flush]; + } + [self pauseMetricsCollection]; return; } @@ -307,7 +319,10 @@ const NSTimeInterval MGLFlushInterval = 180; return; } - if ([self.eventQueue count] == 0) { + if ([self.eventQueue count] <= 1) { + [self.eventQueue removeAllObjects]; + [[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier]; + _backgroundTaskIdentifier = UIBackgroundTaskInvalid; return; } @@ -485,10 +500,12 @@ const NSTimeInterval MGLFlushInterval = 180; if (error) { [strongSelf pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription: @"Network error", @"error": error}]; - return; + } else { + [strongSelf pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription: @"post", + @"debug.eventsCount": @(events.count)}]; } - [strongSelf pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription: @"post", - @"debug.eventsCount": @(events.count)}]; + [[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier]; + _backgroundTaskIdentifier = UIBackgroundTaskInvalid; }]; }); } From 258acb6c487be5fc8c06094f134c60349c63d539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Tue, 18 Oct 2016 15:03:10 -0700 Subject: [PATCH 03/25] [ios, macos] Raise correct style layer misuse exception (#6738) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement the layer property on MGLStyleLayer itself, where it’s declared, so that the check for an abstract style layer doesn’t itself raise an exception. The concrete style layer classes still declare their own layers as covariant properties, although those properties aren’t actually used anywhere. Cherry-picked from ce243043f5251bb6a7fabc90d8ca3162ade8a44f. --- platform/darwin/src/MGLStyle.mm | 8 ++++---- platform/darwin/src/MGLStyleLayer.mm | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm index f9f2e03d4..3964b47ad 100644 --- a/platform/darwin/src/MGLStyle.mm +++ b/platform/darwin/src/MGLStyle.mm @@ -176,7 +176,7 @@ static NSURL *MGLStyleURL_emerald; [NSException raise:NSInvalidArgumentException format: @"The style layer %@ cannot be added to the style. " @"Make sure the style layer was created as a member of a concrete subclass of MGLStyleLayer.", - NSStringFromClass(self)]; + layer]; } self.mapView.mbglMap->addLayer(std::unique_ptr(layer.layer)); @@ -189,14 +189,14 @@ static NSURL *MGLStyleURL_emerald; format: @"The style layer %@ cannot be added to the style. " @"Make sure the style layer was created as a member of a concrete subclass of MGLStyleLayer.", - NSStringFromClass(layer)]; + layer]; } if (!otherLayer.layer) { [NSException raise:NSInvalidArgumentException format: @"A style layer cannot be placed before %@ in the style. " - @"Make sure the style layer was created as a member of a concrete subclass of MGLStyleLayer.", - NSStringFromClass(otherLayer)]; + @"Make sure otherLayer was obtained using -[MGLStyle layerWithIdentifier:].", + otherLayer]; } const mbgl::optional belowLayerId{otherLayer.identifier.UTF8String}; diff --git a/platform/darwin/src/MGLStyleLayer.mm b/platform/darwin/src/MGLStyleLayer.mm index a2bb1fc2c..293aa54f3 100644 --- a/platform/darwin/src/MGLStyleLayer.mm +++ b/platform/darwin/src/MGLStyleLayer.mm @@ -3,6 +3,12 @@ #include +@interface MGLStyleLayer () + +@property (nonatomic) mbgl::style::Layer *layer; + +@end + @implementation MGLStyleLayer - (instancetype)initWithIdentifier:(NSString *)identifier From baf82fc4d4882480e6dd16ea9821be29d390bf00 Mon Sep 17 00:00:00 2001 From: Jesse Bounds Date: Wed, 19 Oct 2016 09:08:56 -0700 Subject: [PATCH 04/25] [ios, macos] Make feature attributes and identifier writable (#6728) * [ios, macos] Make feature attributes and identifier writable Instances of MGLFeature subclasses can now have their attributes and identifier properties mutated. --- platform/darwin/src/MGLFeature.h | 20 +++++--- platform/darwin/src/MGLFeature_Private.h | 3 -- platform/ios/CHANGELOG.md | 1 + platform/ios/app/MBXViewController.m | 58 ++++++++++++++++++++++ platform/ios/test/MGLGeoJSONSourceTests.mm | 6 --- platform/macos/CHANGELOG.md | 1 + 6 files changed, 74 insertions(+), 15 deletions(-) diff --git a/platform/darwin/src/MGLFeature.h b/platform/darwin/src/MGLFeature.h index 239a338f6..05f0baf6c 100644 --- a/platform/darwin/src/MGLFeature.h +++ b/platform/darwin/src/MGLFeature.h @@ -18,8 +18,8 @@ NS_ASSUME_NONNULL_BEGIN 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. + objects can also be added to a map view using an `MGLGeoJSONSource` or + `-[MGLMapView addAnnotations:]` and related methods. */ @protocol MGLFeature @@ -48,9 +48,13 @@ NS_ASSUME_NONNULL_BEGIN For details about the identifiers used in most Mapbox-provided styles, consult the Mapbox Streets - layer reference. + layer reference. Note that while it is possible to change this value on feature + instances obtained from `-[MGLMapView visibleFeaturesAtPoint:]` and related + methods, there will be no effect on the map. Setting this value can be useful + when the feature instance is used to initialize an `MGLGeoJSONSource` and that + source is added to the map and styled. */ -@property (nonatomic, copy, nullable, readonly) id identifier; +@property (nonatomic, copy, nullable) id identifier; /** A dictionary of attributes for this feature specified by the @@ -79,9 +83,13 @@ NS_ASSUME_NONNULL_BEGIN Mapbox Streets and Mapbox Terrain - layer references. + layer references. Note that while it is possible to change this value on feature + instances obtained from `-[MGLMapView visibleFeaturesAtPoint:]` and related + methods, there will be no effect on the map. Setting this value can be useful + when the feature instance is used to initialize an `MGLGeoJSONSource` and that + source is added to the map and styled. */ -@property (nonatomic, copy, readonly) NS_DICTIONARY_OF(NSString *, id) *attributes; +@property (nonatomic, copy) NS_DICTIONARY_OF(NSString *, id) *attributes; /** Returns the feature attribute for the given attribute name. diff --git a/platform/darwin/src/MGLFeature_Private.h b/platform/darwin/src/MGLFeature_Private.h index 5fb82bde5..e6858c7c1 100644 --- a/platform/darwin/src/MGLFeature_Private.h +++ b/platform/darwin/src/MGLFeature_Private.h @@ -26,9 +26,6 @@ NS_DICTIONARY_OF(NSString *, id) *NSDictionaryFeatureForGeometry(NSDictionary *g @protocol MGLFeaturePrivate -@property (nonatomic, copy, nullable, readwrite) id identifier; -@property (nonatomic, copy, readwrite) NS_DICTIONARY_OF(NSString *, id) *attributes; - - (mbgl::Feature)mbglFeature; @end diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 4d8ca723c..a83041edd 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -31,6 +31,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * A source’s tiles are no longer rendered when the map is outside the source’s supported zoom levels. ([#6345](https://github.com/mapbox/mapbox-gl-native/pull/6345)) * Improved style parsing performance. ([#6170](https://github.com/mapbox/mapbox-gl-native/pull/6170)) * Improved feature querying performance. ([#6514](https://github.com/mapbox/mapbox-gl-native/pull/6514)) +* A feature's `identifier` and `attributes` properties can now be mutated. ([#6728](https://github.com/mapbox/mapbox-gl-native/pull/6728)) ### User location diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index 046f60238..63e39e54a 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -62,6 +62,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsRuntimeStylingRows) { MBXSettingsRuntimeStylingFilteredLines, MBXSettingsRuntimeStylingNumericFilteredFill, MBXSettingsRuntimeStylingStyleQuery, + MBXSettingsRuntimeStylingFeatureSource, }; typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { @@ -306,6 +307,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { @"Style Lines With Filter", @"Style Fill With Numeric Filter", @"Style Query For GeoJSON", + @"Style Feature", ]]; break; case MBXSettingsMiscellaneous: @@ -434,6 +436,9 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { case MBXSettingsRuntimeStylingStyleQuery: [self styleQuery]; break; + case MBXSettingsRuntimeStylingFeatureSource: + [self styleFeature]; + break; default: NSAssert(NO, @"All runtime styling setting rows should be implemented"); break; @@ -828,6 +833,59 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { }); } +- (void)styleFeature +{ + self.mapView.zoomLevel = 10; + self.mapView.centerCoordinate = CLLocationCoordinate2DMake(51.068585180672635, -114.06074523925781); + + CLLocationCoordinate2D leafCoords[] = { + CLLocationCoordinate2DMake(50.9683733218221,-114.07035827636719), + CLLocationCoordinate2DMake(51.02325750523972,-114.06967163085938), + CLLocationCoordinate2DMake(51.009434536947786,-114.14245605468749), + CLLocationCoordinate2DMake(51.030599281184124,-114.12597656249999), + CLLocationCoordinate2DMake(51.060386316691016,-114.21043395996094), + CLLocationCoordinate2DMake(51.063838646941576,-114.17816162109375), + CLLocationCoordinate2DMake(51.08152779888779,-114.19876098632812), + CLLocationCoordinate2DMake(51.08066507029602,-114.16854858398438), + CLLocationCoordinate2DMake(51.09662294502995,-114.17472839355469), + CLLocationCoordinate2DMake(51.07764539352731,-114.114990234375), + CLLocationCoordinate2DMake(51.13670896949613,-114.12391662597656), + CLLocationCoordinate2DMake(51.13369295212583,-114.09576416015624), + CLLocationCoordinate2DMake(51.17546878815025,-114.07585144042969), + CLLocationCoordinate2DMake(51.140155605265896,-114.04632568359375), + CLLocationCoordinate2DMake(51.15049396880196,-114.01542663574219), + CLLocationCoordinate2DMake(51.088860342359965,-114.00924682617186), + CLLocationCoordinate2DMake(51.12205789681453,-113.94813537597656), + CLLocationCoordinate2DMake(51.106539930027225,-113.94882202148438), + CLLocationCoordinate2DMake(51.117747873223344,-113.92616271972656), + CLLocationCoordinate2DMake(51.10093493903458,-113.92616271972656), + CLLocationCoordinate2DMake(51.10697105503078,-113.90625), + CLLocationCoordinate2DMake(51.09144802136697,-113.9117431640625), + CLLocationCoordinate2DMake(51.04916446529361,-113.97010803222655), + CLLocationCoordinate2DMake(51.045279344649146,-113.9398956298828), + CLLocationCoordinate2DMake(51.022825599852496,-114.06211853027344), + CLLocationCoordinate2DMake(51.045279344649146,-113.9398956298828), + CLLocationCoordinate2DMake(51.022825599852496,-114.06211853027344), + CLLocationCoordinate2DMake(51.022825599852496,-114.06280517578125), + CLLocationCoordinate2DMake(50.968805734317804,-114.06280517578125), + CLLocationCoordinate2DMake(50.9683733218221,-114.07035827636719), + }; + NSUInteger coordsCount = sizeof(leafCoords) / sizeof(leafCoords[0]); + + MGLPolygonFeature *feature = [MGLPolygonFeature polygonWithCoordinates:leafCoords count:coordsCount]; + feature.identifier = @"leaf-feature"; + feature.attributes = @{@"color": @"red"}; + + MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"leaf-source" features:@[feature] options:nil]; + [self.mapView.style addSource:source]; + + MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"leaf-fill-layer" source:source]; + layer.predicate = [NSPredicate predicateWithFormat:@"color = %@", @"red"]; + MGLStyleValue *fillColor = [MGLStyleValue valueWithRawValue:[UIColor redColor]]; + layer.fillColor = fillColor; + [self.mapView.style addLayer:layer]; +} + - (IBAction)startWorldTour { _isTouringWorld = YES; diff --git a/platform/ios/test/MGLGeoJSONSourceTests.mm b/platform/ios/test/MGLGeoJSONSourceTests.mm index 40d806798..935d9a0ae 100644 --- a/platform/ios/test/MGLGeoJSONSourceTests.mm +++ b/platform/ios/test/MGLGeoJSONSourceTests.mm @@ -10,12 +10,6 @@ @interface MGLGeoJSONSourceTests : XCTestCase @end -@interface MGLPolygonFeature (Test) - -@property (nonatomic, copy, readwrite) NS_DICTIONARY_OF(NSString *, id) *attributes; - -@end - @implementation MGLGeoJSONSourceTests - (void)testMGLGeoJSONSourceWithOptions { diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 5d58bafd7..c96761a94 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -23,6 +23,7 @@ * Fixed crashes that could occur when loading a malformed stylesheet. ([#5736](https://github.com/mapbox/mapbox-gl-native/pull/5736)) * Improved style parsing performance. ([#6170](https://github.com/mapbox/mapbox-gl-native/pull/6170)) * Improved feature querying performance. ([#6514](https://github.com/mapbox/mapbox-gl-native/pull/6514)) +* A feature's `identifier` and `attributes` properties can now be mutated. ([#6728](https://github.com/mapbox/mapbox-gl-native/pull/6728)) ### Annotations From 1216050f9c5c472f1c8edcc32447004a40680ec7 Mon Sep 17 00:00:00 2001 From: Jesse Bounds Date: Thu, 20 Oct 2016 17:14:19 -0700 Subject: [PATCH 05/25] 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. --- platform/darwin/src/MGLFeature.h | 5 +- platform/darwin/src/MGLFeature.mm | 8 +- platform/darwin/src/MGLMultiPoint.h | 21 +--- platform/darwin/src/MGLMultiPoint.mm | 28 ----- platform/darwin/src/MGLPointCollection.h | 51 ++++++++ platform/darwin/src/MGLPointCollection.mm | 112 ++++++++++++++++++ .../darwin/src/MGLPointCollection_Private.h | 11 ++ platform/darwin/src/MGLPolygon.h | 2 +- platform/darwin/src/MGLPolyline.h | 2 +- platform/darwin/test/MGLFeatureTests.mm | 37 +++--- platform/ios/CHANGELOG.md | 2 + platform/ios/app/MBXViewController.m | 22 ++++ platform/ios/ios.xcodeproj/project.pbxproj | 18 ++- platform/ios/jazzy.yml | 3 +- platform/ios/src/MGLMapView.h | 9 +- platform/ios/src/MGLMapView.mm | 12 +- platform/ios/src/Mapbox.h | 1 + platform/ios/test/MGLGeoJSONSourceTests.mm | 72 ++++------- platform/macos/CHANGELOG.md | 2 + platform/macos/jazzy.yml | 7 +- .../macos/macos.xcodeproj/project.pbxproj | 16 ++- platform/macos/src/MGLMapView.mm | 11 +- platform/macos/src/Mapbox.h | 1 + 23 files changed, 302 insertions(+), 151 deletions(-) create mode 100644 platform/darwin/src/MGLPointCollection.h create mode 100644 platform/darwin/src/MGLPointCollection.mm create mode 100644 platform/darwin/src/MGLPointCollection_Private.h diff --git a/platform/darwin/src/MGLFeature.h b/platform/darwin/src/MGLFeature.h index 05f0baf6c..384c5a073 100644 --- a/platform/darwin/src/MGLFeature.h +++ b/platform/darwin/src/MGLFeature.h @@ -3,6 +3,7 @@ #import "MGLPolyline.h" #import "MGLPolygon.h" #import "MGLPointAnnotation.h" +#import "MGLPointCollection.h" #import "MGLShapeCollection.h" NS_ASSUME_NONNULL_BEGIN @@ -134,10 +135,10 @@ NS_ASSUME_NONNULL_BEGIN @end /** - The `MGLMultiPointFeature` class represents a multipoint in a + The `MGLPointCollectionFeature` class represents a multipoint in a tile source. */ -@interface MGLMultiPointFeature : MGLMultiPoint +@interface MGLPointCollectionFeature : MGLPointCollection @end /** diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm index 84dcc4f0b..548343371 100644 --- a/platform/darwin/src/MGLFeature.mm +++ b/platform/darwin/src/MGLFeature.mm @@ -6,7 +6,7 @@ #import "MGLValueEvaluator.h" #import "MGLShape_Private.h" -#import "MGLMultiPoint_Private.h" +#import "MGLPointCollection_Private.h" #import "MGLPolyline+MGLAdditions.h" #import "MGLPolygon+MGLAdditions.h" #import "NSDictionary+MGLAdditions.h" @@ -82,10 +82,10 @@ @end -@interface MGLMultiPointFeature () +@interface MGLPointCollectionFeature () @end -@implementation MGLMultiPointFeature +@implementation MGLPointCollectionFeature @synthesize identifier; @synthesize attributes; @@ -202,7 +202,7 @@ public: MGLShape * operator()(const mbgl::MultiPoint &geometry) const { std::vector coordinates = toLocationCoordinates2D(geometry); - return [[MGLMultiPointFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()]; + return [[MGLPointCollectionFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()]; } MGLShape * operator()(const mbgl::MultiLineString &geometry) const { diff --git a/platform/darwin/src/MGLMultiPoint.h b/platform/darwin/src/MGLMultiPoint.h index b936205ab..69c729584 100644 --- a/platform/darwin/src/MGLMultiPoint.h +++ b/platform/darwin/src/MGLMultiPoint.h @@ -6,24 +6,15 @@ NS_ASSUME_NONNULL_BEGIN /** - The `MGLMultiPoint` class is used to define shapes composed of multiple points. - This class is also the superclass of `MGLPolyline` and `MGLPolygon`. The - methods and properties of this class can be used to access information about - the specific points associated with a line or polygon. + The `MGLMultiPoint` class is an abstract superclass used to define shapes + composed of multiple points. You should not create instances of this class + directly. Instead, you should create instances of the `MGLPolyline` or + `MGLPolygon` classes. However, you can use the method and properties of this + class to access information about the specific points associated with the line + or polygon. */ @interface MGLMultiPoint : MGLShape -/** - Creates and returns an `MGLMultiPoint` object from the specified set of - coordinates. - - @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. - @return A new multipoint object. - */ -+ (instancetype)multiPointWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count NS_SWIFT_NAME(multiPoint(coordinates:count:)); - /** The array of coordinates associated with the shape. diff --git a/platform/darwin/src/MGLMultiPoint.mm b/platform/darwin/src/MGLMultiPoint.mm index 0090c5e35..17a61ed08 100644 --- a/platform/darwin/src/MGLMultiPoint.mm +++ b/platform/darwin/src/MGLMultiPoint.mm @@ -18,11 +18,6 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) MGLCoordinateBounds _bounds; } -+ (instancetype)multiPointWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count -{ - return [[self alloc] initWithCoordinates:coords count:count]; -} - - (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count { self = [super init]; @@ -146,29 +141,6 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) return mbgl::SymbolAnnotation({mbgl::Point()}); } -- (mbgl::Feature)featureObject -{ - mbgl::MultiPoint multiPoint; - multiPoint.reserve(self.pointCount); - for (NSInteger i = 0; i< self.pointCount; i++) - { - multiPoint.push_back(mbgl::Point(self.coordinates[i].longitude, self.coordinates[i].latitude)); - } - return mbgl::Feature {multiPoint}; -} - -- (NSDictionary *)geoJSONDictionary -{ - NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:self.pointCount]; - for (NSUInteger index = 0; index < self.pointCount; index++) { - CLLocationCoordinate2D coordinate = self.coordinates[index]; - [coordinates addObject:@[@(coordinate.longitude), @(coordinate.latitude)]]; - } - - return @{@"type": @"MultiPoint", - @"coordinates": coordinates}; -} - - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p; count = %lu; bounds = %@>", diff --git a/platform/darwin/src/MGLPointCollection.h b/platform/darwin/src/MGLPointCollection.h new file mode 100644 index 000000000..db497d0a5 --- /dev/null +++ b/platform/darwin/src/MGLPointCollection.h @@ -0,0 +1,51 @@ +#import +#import + +#import "MGLOverlay.h" +#import "MGLShape.h" + +/** + The `MGLPointCollection` class is used to define an array of disconnected + coordinates. The points in the collection may be related but are not + connected visually in any way. + + @note `MGLPointCollection` objects cannot be added to a map view using + `-[MGLMapView addAnnotations:]` and related methods. However, when used in a + `MGLPointCollectionFeature` to initialize a `MGLGeoJSONSource` that is added + to the map view's style, the point collection represents as a group of distinct + annotations. + */ +@interface MGLPointCollection : MGLShape + +/** + Creates and returns a `MGLPointCollection` object from the specified set of + coordinates. + + @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. + @return A new point collection object. + */ ++ (instancetype)pointCollectionWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count; + +/** 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. */ +@property (nonatomic, readonly) NSUInteger pointCount; + +/** + Retrieves one or more coordinates associated with the shape. + + @param coords On input, you must provide a C array of structures large enough + to hold the desired number of coordinates. On output, this structure + contains the requested coordinate data. + @param range The range of points you want. The `location` field indicates the + first point you are requesting, with `0` being the first point, `1` being + the second point, and so on. The `length` field indicates the number of + points you want. The array in _`coords`_ must be large enough to accommodate + the number of requested coordinates. + */ +- (void)getCoordinates:(CLLocationCoordinate2D *)coords range:(NSRange)range; + +@end diff --git a/platform/darwin/src/MGLPointCollection.mm b/platform/darwin/src/MGLPointCollection.mm new file mode 100644 index 000000000..5871915b5 --- /dev/null +++ b/platform/darwin/src/MGLPointCollection.mm @@ -0,0 +1,112 @@ +#import "MGLPointCollection_Private.h" +#import "MGLGeometry_Private.h" + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@implementation MGLPointCollection +{ + size_t _count; + MGLCoordinateBounds _bounds; +} + ++ (instancetype)pointCollectionWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count +{ + return [[self alloc] initWithCoordinates:coords count:count]; +} + +- (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count +{ + self = [super init]; + if (self) + { + _count = count; + _coordinates = (CLLocationCoordinate2D *)malloc(_count * sizeof(CLLocationCoordinate2D)); + + mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty(); + + for (NSUInteger i = 0; i < count; i++) + { + _coordinates[i] = coords[i]; + bounds.extend(mbgl::LatLng(coords[i].latitude, coords[i].longitude)); + } + + _bounds = MGLCoordinateBoundsFromLatLngBounds(bounds); + } + return self; +} + +- (NSUInteger)pointCount +{ + return _count; +} + +- (CLLocationCoordinate2D)coordinate +{ + assert(_count > 0); + + return CLLocationCoordinate2DMake(_coordinates[0].latitude, _coordinates[0].longitude); +} + +- (void)getCoordinates:(CLLocationCoordinate2D *)coords range:(NSRange)range +{ + if (range.location + range.length > _count) + { + [NSException raise:NSRangeException + format:@"Invalid coordinate range %@ extends beyond current coordinate count of %zu", + NSStringFromRange(range), _count]; + } + + NSUInteger index = 0; + + for (NSUInteger i = range.location; i < range.location + range.length; i++) + { + coords[index] = _coordinates[i]; + index++; + } +} + +- (MGLCoordinateBounds)overlayBounds +{ + return _bounds; +} + +- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds +{ + return MGLLatLngBoundsFromCoordinateBounds(_bounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds)); +} + +- (mbgl::Feature)featureObject +{ + mbgl::MultiPoint multiPoint; + multiPoint.reserve(self.pointCount); + for (NSInteger i = 0; i< self.pointCount; i++) + { + multiPoint.push_back(mbgl::Point(self.coordinates[i].longitude, self.coordinates[i].latitude)); + } + return mbgl::Feature {multiPoint}; +} + +- (NSDictionary *)geoJSONDictionary +{ + NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:self.pointCount]; + for (NSUInteger index = 0; index < self.pointCount; index++) { + CLLocationCoordinate2D coordinate = self.coordinates[index]; + [coordinates addObject:@[@(coordinate.longitude), @(coordinate.latitude)]]; + } + + return @{@"type": @"MultiPoint", + @"coordinates": coordinates}; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p; count = %lu>", + NSStringFromClass([self class]), (void *)self, (unsigned long)_count]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLPointCollection_Private.h b/platform/darwin/src/MGLPointCollection_Private.h new file mode 100644 index 000000000..039c1f18b --- /dev/null +++ b/platform/darwin/src/MGLPointCollection_Private.h @@ -0,0 +1,11 @@ +#import "MGLPointCollection.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MGLPointCollection (Private) + +- (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLPolygon.h b/platform/darwin/src/MGLPolygon.h index 6d53356ba..3d5b36abb 100644 --- a/platform/darwin/src/MGLPolygon.h +++ b/platform/darwin/src/MGLPolygon.h @@ -36,7 +36,7 @@ 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 NS_SWIFT_NAME(polygon(coordinates:count:)); ++ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count; /** Creates and returns an `MGLPolygon` object from the specified set of diff --git a/platform/darwin/src/MGLPolyline.h b/platform/darwin/src/MGLPolyline.h index 6642afef7..d0274b44e 100644 --- a/platform/darwin/src/MGLPolyline.h +++ b/platform/darwin/src/MGLPolyline.h @@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN @param count The number of items in the `coords` array. @return A new polyline object. */ -+ (instancetype)polylineWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count NS_SWIFT_NAME(polyline(coordinates:count:)); ++ (instancetype)polylineWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count; @end diff --git a/platform/darwin/test/MGLFeatureTests.mm b/platform/darwin/test/MGLFeatureTests.mm index 18c3fd16c..7f464aaab 100644 --- a/platform/darwin/test/MGLFeatureTests.mm +++ b/platform/darwin/test/MGLFeatureTests.mm @@ -227,24 +227,6 @@ XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry); } -- (void)testMultiPointFeatureGeoJSONDictionary { - CLLocationCoordinate2D coord1 = { 0, 0 }; - CLLocationCoordinate2D coord2 = { 10, 10 }; - CLLocationCoordinate2D coord3 = { 0, 0 }; - CLLocationCoordinate2D coords[] = { coord1, coord2, coord3 }; - MGLMultiPointFeature *multiPointFeature = [MGLMultiPointFeature multiPointWithCoordinates:coords count:3]; - - // A GeoJSON feature - NSDictionary *geoJSONFeature = [multiPointFeature geoJSONDictionary]; - - // it has the correct geometry - NSDictionary *expectedGeometry = @{@"type": @"MultiPoint", - @"coordinates": @[@[@(coord1.longitude), @(coord1.latitude)], - @[@(coord2.longitude), @(coord2.latitude)], - @[@(coord3.longitude), @(coord3.latitude)]]}; - XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry); -} - - (void)testMultiPolylineFeatureGeoJSONDictionary { CLLocationCoordinate2D coord1 = { 0, 0 }; CLLocationCoordinate2D coord2 = { 10, 10 }; @@ -296,6 +278,25 @@ XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry); } +- (void)testPointCollectionFeatureGeoJSONDictionary { + CLLocationCoordinate2D coord1 = { 0, 0 }; + CLLocationCoordinate2D coord2 = { 10, 10 }; + CLLocationCoordinate2D coord3 = { 0, 0 }; + CLLocationCoordinate2D coords[] = { coord1, coord2, coord3 }; + MGLPointCollectionFeature *pointCollectionFeature = [MGLPointCollectionFeature pointCollectionWithCoordinates:coords count:3]; + + // A GeoJSON feature + NSDictionary *geoJSONFeature = [pointCollectionFeature geoJSONDictionary]; + + // it has the correct geometry + NSDictionary *expectedGeometry = @{@"type": @"MultiPoint", + @"coordinates": @[@[@(coord1.longitude), @(coord1.latitude)], + @[@(coord2.longitude), @(coord2.latitude)], + @[@(coord3.longitude), @(coord3.latitude)]]}; + XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry); + +} + - (void)testShapeCollectionFeatureGeoJSONDictionary { MGLPointAnnotation *pointFeature = [[MGLPointAnnotation alloc] init]; CLLocationCoordinate2D pointCoordinate = { 10, 10 }; diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index a83041edd..8587f31d3 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -32,6 +32,8 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Improved style parsing performance. ([#6170](https://github.com/mapbox/mapbox-gl-native/pull/6170)) * Improved feature querying performance. ([#6514](https://github.com/mapbox/mapbox-gl-native/pull/6514)) * A feature's `identifier` and `attributes` properties can now be mutated. ([#6728](https://github.com/mapbox/mapbox-gl-native/pull/6728)) +* 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)) +* 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)) ### User location diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index 63e39e54a..3a58c1163 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -63,6 +63,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsRuntimeStylingRows) { MBXSettingsRuntimeStylingNumericFilteredFill, MBXSettingsRuntimeStylingStyleQuery, MBXSettingsRuntimeStylingFeatureSource, + MBXSettingsRuntimeStylingPointCollection, }; typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { @@ -308,6 +309,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { @"Style Fill With Numeric Filter", @"Style Query For GeoJSON", @"Style Feature", + @"Style Dynamic Point Collection", ]]; break; case MBXSettingsMiscellaneous: @@ -439,6 +441,9 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { case MBXSettingsRuntimeStylingFeatureSource: [self styleFeature]; break; + case MBXSettingsRuntimeStylingPointCollection: + [self styleDynamicPointCollection]; + break; default: NSAssert(NO, @"All runtime styling setting rows should be implemented"); break; @@ -886,6 +891,23 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { [self.mapView.style addLayer:layer]; } +- (void)styleDynamicPointCollection +{ + [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(36.9979, -109.0441) zoomLevel:14 animated:NO]; + CLLocationCoordinate2D coordinates[] = { + {37.00145594210082, -109.04960632324219}, + {37.00173012609867, -109.0404224395752}, + {36.99453246847359, -109.04960632324219}, + {36.99508088541243, -109.04007911682129}, + }; + MGLPointCollectionFeature *feature = [MGLPointCollectionFeature pointCollectionWithCoordinates:coordinates count:4]; + MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"wiggle-source" features:@[feature] options:nil]; + [self.mapView.style addSource:source]; + + MGLCircleStyleLayer *layer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"wiggle-layer" source:source]; + [self.mapView.style addLayer:layer]; +} + - (IBAction)startWorldTour { _isTouringWorld = YES; diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index 3c19f5ea4..825377476 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -128,6 +128,11 @@ 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, ); }; }; 404326891D5B9B27007111BD /* MGLAnnotationContainerView_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 404326881D5B9B1A007111BD /* MGLAnnotationContainerView_Private.h */; }; + 4049C29D1DB6CD6C00B3F799 /* MGLPointCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4049C29B1DB6CD6C00B3F799 /* MGLPointCollection.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4049C29E1DB6CD6C00B3F799 /* MGLPointCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4049C29B1DB6CD6C00B3F799 /* MGLPointCollection.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4049C29F1DB6CD6C00B3F799 /* MGLPointCollection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4049C29C1DB6CD6C00B3F799 /* MGLPointCollection.mm */; }; + 4049C2A01DB6CD6C00B3F799 /* MGLPointCollection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4049C29C1DB6CD6C00B3F799 /* MGLPointCollection.mm */; }; + 4049C2AC1DB6E05500B3F799 /* MGLPointCollection_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4049C2AB1DB6E05500B3F799 /* MGLPointCollection_Private.h */; }; 404C26E21D89B877000AA13D /* MGLTileSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 404C26E01D89B877000AA13D /* MGLTileSet.h */; settings = {ATTRIBUTES = (Public, ); }; }; 404C26E31D89B877000AA13D /* MGLTileSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 404C26E01D89B877000AA13D /* MGLTileSet.h */; settings = {ATTRIBUTES = (Public, ); }; }; 404C26E41D89B877000AA13D /* MGLTileSet.mm in Sources */ = {isa = PBXBuildFile; fileRef = 404C26E11D89B877000AA13D /* MGLTileSet.mm */; }; @@ -555,6 +560,9 @@ 4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationView.h; sourceTree = ""; }; 402E9DE01CD2C76200FD4519 /* Mapbox.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Mapbox.playground; sourceTree = ""; }; 404326881D5B9B1A007111BD /* MGLAnnotationContainerView_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationContainerView_Private.h; sourceTree = ""; }; + 4049C29B1DB6CD6C00B3F799 /* MGLPointCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPointCollection.h; sourceTree = ""; }; + 4049C29C1DB6CD6C00B3F799 /* MGLPointCollection.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLPointCollection.mm; sourceTree = ""; }; + 4049C2AB1DB6E05500B3F799 /* MGLPointCollection_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPointCollection_Private.h; sourceTree = ""; }; 404C26E01D89B877000AA13D /* MGLTileSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTileSet.h; sourceTree = ""; }; 404C26E11D89B877000AA13D /* MGLTileSet.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLTileSet.mm; sourceTree = ""; }; 404C26E61D89C515000AA13D /* MGLTileSet_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLTileSet_Private.h; sourceTree = ""; }; @@ -1257,12 +1265,15 @@ DA8847E11CBAFA5100AB86E3 /* MGLGeometry.h */, DA8848011CBAFA6200AB86E3 /* MGLGeometry_Private.h */, DA8848021CBAFA6200AB86E3 /* MGLGeometry.mm */, - DA8847E31CBAFA5100AB86E3 /* MGLMultiPoint.h */, DA8848041CBAFA6200AB86E3 /* MGLMultiPoint_Private.h */, + DA8847E31CBAFA5100AB86E3 /* MGLMultiPoint.h */, DA8848051CBAFA6200AB86E3 /* MGLMultiPoint.mm */, DA8847E71CBAFA5100AB86E3 /* MGLOverlay.h */, DA8847E81CBAFA5100AB86E3 /* MGLPointAnnotation.h */, DA88480B1CBAFA6200AB86E3 /* MGLPointAnnotation.mm */, + 4049C29B1DB6CD6C00B3F799 /* MGLPointCollection.h */, + 4049C2AB1DB6E05500B3F799 /* MGLPointCollection_Private.h */, + 4049C29C1DB6CD6C00B3F799 /* MGLPointCollection.mm */, DA8847E91CBAFA5100AB86E3 /* MGLPolygon.h */, DA88480C1CBAFA6200AB86E3 /* MGLPolygon.mm */, DA8847EA1CBAFA5100AB86E3 /* MGLPolyline.h */, @@ -1410,6 +1421,7 @@ DA8847F01CBAFA5100AB86E3 /* MGLAnnotation.h in Headers */, 7E016D841D9E890300A29A21 /* MGLPolygon+MGLAdditions.h in Headers */, 400533011DB0862B0069F638 /* NSArray+MGLAdditions.h in Headers */, + 4049C29D1DB6CD6C00B3F799 /* MGLPointCollection.h in Headers */, DA88483E1CBAFB8500AB86E3 /* MGLMapView+MGLCustomStyleLayerAdditions.h in Headers */, 40CF6DBB1DAC3C6600A4D18B /* MGLShape_Private.h in Headers */, 4018B1CA1CDC288E00F666AF /* MGLAnnotationView.h in Headers */, @@ -1449,6 +1461,7 @@ 35136D4C1D4277FC00C20EFD /* MGLSource.h in Headers */, 3566C76C1D4A8DFA008152BC /* MGLRasterSource.h in Headers */, DA8847F91CBAFA5100AB86E3 /* MGLPolygon.h in Headers */, + 4049C2AC1DB6E05500B3F799 /* MGLPointCollection_Private.h in Headers */, DA8847F81CBAFA5100AB86E3 /* MGLPointAnnotation.h in Headers */, 353933F21D3FB753003F57D7 /* MGLCircleStyleLayer.h in Headers */, DA8847F31CBAFA5100AB86E3 /* MGLMultiPoint.h in Headers */, @@ -1493,6 +1506,7 @@ DABFB85E1CBE99E500D62B32 /* MGLAnnotation.h in Headers */, DABFB8641CBE99E500D62B32 /* MGLOfflineStorage.h in Headers */, DAD165791CF4CDFF001FF4B9 /* MGLShapeCollection.h in Headers */, + 4049C29E1DB6CD6C00B3F799 /* MGLPointCollection.h in Headers */, 3566C7671D4A77BA008152BC /* MGLGeoJSONSource.h in Headers */, DA35A29F1CC9E94C00E826B2 /* MGLCoordinateFormatter.h in Headers */, DABFB8711CBE9A0F00D62B32 /* MGLMapView+MGLCustomStyleLayerAdditions.h in Headers */, @@ -1943,6 +1957,7 @@ 35D13AC51D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */, DA8848241CBAFA6200AB86E3 /* MGLOfflineStorage.mm in Sources */, DA88482A1CBAFA6200AB86E3 /* MGLTilePyramidOfflineRegion.mm in Sources */, + 4049C29F1DB6CD6C00B3F799 /* MGLPointCollection.mm in Sources */, 35136D3F1D42273000C20EFD /* MGLLineStyleLayer.mm in Sources */, DA88481A1CBAFA6200AB86E3 /* MGLAccountManager.m in Sources */, 3510FFFB1D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.mm in Sources */, @@ -2014,6 +2029,7 @@ 35D13AC61D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */, DAA4E42A1CBB730400178DFB /* NSProcessInfo+MGLAdditions.m in Sources */, DAA4E4211CBB730400178DFB /* MGLOfflineStorage.mm in Sources */, + 4049C2A01DB6CD6C00B3F799 /* MGLPointCollection.mm in Sources */, 35136D401D42273000C20EFD /* MGLLineStyleLayer.mm in Sources */, DAA4E42F1CBB730400178DFB /* MGLCompactCalloutView.m in Sources */, 3510FFFC1D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.mm in Sources */, diff --git a/platform/ios/jazzy.yml b/platform/ios/jazzy.yml index c41dddc89..c19d9e388 100644 --- a/platform/ios/jazzy.yml +++ b/platform/ios/jazzy.yml @@ -34,6 +34,7 @@ custom_categories: - MGLMultiPolygon - MGLMultiPolyline - MGLPointAnnotation + - MGLPointCollection - MGLPolygon - MGLPolyline - MGLOverlay @@ -44,9 +45,9 @@ custom_categories: - name: Map Data children: - MGLFeature - - MGLMultiPointFeature - MGLMultiPolygonFeature - MGLMultiPolylineFeature + - MGLPointCollectionFeature - MGLPointFeature - MGLPolygonFeature - MGLPolylineFeature diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h index 57b74daa0..5a89632db 100644 --- a/platform/ios/src/MGLMapView.h +++ b/platform/ios/src/MGLMapView.h @@ -895,11 +895,10 @@ 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. Nor can `MGLMultiPoint` - objects that are not instances of `MGLPolyline` or `MGLPolygon`. Any - multipoint, multipolyline, multipolygon, or shape collection object that is - specified is silently ignored. + @note `MGLMultiPolyline`, `MGLMultiPolygon`, `MGLShapeCollection`, and + `MGLPointCollection` objects cannot be added to the map view at this time. + Any multipoint, multipolyline, multipolygon, shape or point collection + object that is specified 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 diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 88f4d8a97..bb7e44662 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -2855,13 +2855,6 @@ public: if ([annotation isKindOfClass:[MGLMultiPoint class]]) { - // Actual multipoints aren’t supported as annotations. - if ([annotation isMemberOfClass:[MGLMultiPoint class]] - || [annotation isMemberOfClass:[MGLMultiPointFeature class]]) - { - continue; - } - // The polyline or polygon knows how to style itself (with the map view’s help). MGLMultiPoint *multiPoint = (MGLMultiPoint *)annotation; if (!multiPoint.pointCount) { @@ -2876,8 +2869,9 @@ public: [(NSObject *)annotation addObserver:self forKeyPath:@"coordinates" options:0 context:(void *)(NSUInteger)annotationTag]; } else if ( ! [annotation isKindOfClass:[MGLMultiPolyline class]] - || ![annotation isKindOfClass:[MGLMultiPolygon class]] - || ![annotation isKindOfClass:[MGLShapeCollection class]]) + && ![annotation isKindOfClass:[MGLMultiPolygon class]] + && ![annotation isKindOfClass:[MGLShapeCollection class]] + && ![annotation isKindOfClass:[MGLPointCollection class]]) { MGLAnnotationView *annotationView; NSString *symbolName; diff --git a/platform/ios/src/Mapbox.h b/platform/ios/src/Mapbox.h index 04892eb6a..c2fda1be1 100644 --- a/platform/ios/src/Mapbox.h +++ b/platform/ios/src/Mapbox.h @@ -27,6 +27,7 @@ FOUNDATION_EXPORT const unsigned char MapboxVersionString[]; #import "MGLOfflineStorage.h" #import "MGLOverlay.h" #import "MGLPointAnnotation.h" +#import "MGLPointCollection.h" #import "MGLPolygon.h" #import "MGLPolyline.h" #import "MGLShape.h" diff --git a/platform/ios/test/MGLGeoJSONSourceTests.mm b/platform/ios/test/MGLGeoJSONSourceTests.mm index 935d9a0ae..c885873f7 100644 --- a/platform/ios/test/MGLGeoJSONSourceTests.mm +++ b/platform/ios/test/MGLGeoJSONSourceTests.mm @@ -139,54 +139,6 @@ XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLPolygonFeature class]]); } - -- (void)testMGLGeoJSONSourceWithMultiPointFeaturesUsingPolylines { - 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)}; - - MGLMultiPointFeature *multiPointFeature = [MGLMultiPointFeature multiPointWithCoordinates:coordinates count:5]; - - MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" features:@[multiPointFeature] options:nil]; - - std::unique_ptr mbglSource = [source mbglSource]; - - XCTAssertNotNil(source.features); - XCTAssertEqual(source.features.count, 1); - XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLMultiPointFeature class]]); -} - -- (void)testMGLGeoJSONSourceWithMultiPointFeaturesUsingPolygons { - 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)}; - - CLLocationCoordinate2D interiorCoordinates[] = { - CLLocationCoordinate2DMake(100.2, 0.2), - CLLocationCoordinate2DMake(100.8, 0.2), - CLLocationCoordinate2DMake(100.8, 0.8), - CLLocationCoordinate2DMake(100.2, 0.8), - CLLocationCoordinate2DMake(100.2, 0.2)}; - - MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:interiorCoordinates count:5]; - - MGLMultiPointFeature *multiPointFeature = (MGLMultiPointFeature *)[MGLPolygonFeature polygonWithCoordinates:coordinates count:5 interiorPolygons:@[polygon]]; - - MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" features:@[multiPointFeature] options:nil]; - - std::unique_ptr mbglSource = [source mbglSource]; - - XCTAssertNotNil(source.features); - XCTAssertEqual(source.features.count, 1); - XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLPolygonFeature class]]); -} - - (void)testMGLGeoJSONSourceWithMultiPolylineFeatures { CLLocationCoordinate2D firstCoordinates[] = { CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10)}; MGLPolylineFeature *firstPolylineFeature = [MGLPolylineFeature polylineWithCoordinates:firstCoordinates count:2]; @@ -248,6 +200,24 @@ XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLPointFeature class]]); } +- (void)testMGLGeoJSONSourceWithPointCollectionFeature { + 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)}; + MGLPointCollectionFeature *pointCollectionFeature = [MGLPointCollectionFeature pointCollectionWithCoordinates:coordinates count:5]; +; + MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"souce-id" features:@[pointCollectionFeature] options:nil]; + + std::unique_ptr mbglSource = [source mbglSource]; + + XCTAssertNotNil(source.features); + XCTAssertEqual(source.features.count, 1); + XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLPointCollectionFeature class]]); +} + - (void)testMGLGeoJSONSourceWithShapeCollectionFeatures { CLLocationCoordinate2D coordinates[] = { CLLocationCoordinate2DMake(100.0, 0.0), @@ -274,14 +244,14 @@ MGLMultiPolylineFeature *multiPolylineFeature = [MGLMultiPolylineFeature multiPolylineWithPolylines:@[polylineFeature, polylineFeature]]; - MGLMultiPointFeature *multiPointFeature = (MGLMultiPointFeature *)[MGLPolygonFeature polygonWithCoordinates:coordinates count:5 interiorPolygons:@[polygon]]; + MGLPointCollectionFeature *pointCollectionFeature = [MGLPointCollectionFeature pointCollectionWithCoordinates:coordinates count:5]; MGLPointFeature *pointFeature = [MGLPointFeature new]; pointFeature.coordinate = CLLocationCoordinate2DMake(100.2, 0.2); - MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[polygonFeature, polylineFeature, multiPolygonFeature, multiPolylineFeature, multiPointFeature, pointFeature]]; + MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[polygonFeature, polylineFeature, multiPolygonFeature, multiPolylineFeature, pointCollectionFeature, pointFeature]]; - MGLShapeCollectionFeature *shapeCollectionFeature_1 = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[polygonFeature, polylineFeature, multiPolygonFeature, multiPolylineFeature, multiPointFeature, pointFeature, shapeCollectionFeature]]; + MGLShapeCollectionFeature *shapeCollectionFeature_1 = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[polygonFeature, polylineFeature, multiPolygonFeature, multiPolylineFeature, pointCollectionFeature, pointFeature, shapeCollectionFeature]]; MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"" features:@[shapeCollectionFeature_1] options:nil]; diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index c96761a94..df215f36d 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -24,6 +24,8 @@ * Improved style parsing performance. ([#6170](https://github.com/mapbox/mapbox-gl-native/pull/6170)) * Improved feature querying performance. ([#6514](https://github.com/mapbox/mapbox-gl-native/pull/6514)) * A feature's `identifier` and `attributes` properties can now be mutated. ([#6728](https://github.com/mapbox/mapbox-gl-native/pull/6728)) +* 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)) +* 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)) ### Annotations diff --git a/platform/macos/jazzy.yml b/platform/macos/jazzy.yml index 6909e1438..42f978283 100644 --- a/platform/macos/jazzy.yml +++ b/platform/macos/jazzy.yml @@ -30,6 +30,7 @@ custom_categories: - MGLMultiPolygon - MGLMultiPolyline - MGLPointAnnotation + - MGLPointCollection - MGLPolygon - MGLPolyline - MGLOverlay @@ -37,11 +38,11 @@ custom_categories: - MGLShapeCollection - name: Map Data children: - - MGLFeature - - MGLMultiPointFeature + - MGLFeature - MGLMultiPolygonFeature - MGLMultiPolylineFeature - - MGLPointFeature + - MGLPointCollectionFeature + - MGLPointFeature - MGLPolygonFeature - MGLPolylineFeature - MGLShapeCollectionFeature diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj index eedad040b..9c610a820 100644 --- a/platform/macos/macos.xcodeproj/project.pbxproj +++ b/platform/macos/macos.xcodeproj/project.pbxproj @@ -40,6 +40,8 @@ 35C5D84A1D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35C5D8461D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.mm */; }; 35D65C5A1D65AD5500722C23 /* NSDate+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 35D65C581D65AD5500722C23 /* NSDate+MGLAdditions.h */; }; 35D65C5B1D65AD5500722C23 /* NSDate+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35D65C591D65AD5500722C23 /* NSDate+MGLAdditions.mm */; }; + 4049C2A51DB6CE7F00B3F799 /* MGLPointCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4049C2A11DB6CE7800B3F799 /* MGLPointCollection.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4049C2AD1DB8020600B3F799 /* MGLPointCollection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4049C2A71DB6D09B00B3F799 /* MGLPointCollection.mm */; }; 408AA85B1DAEECFE00022900 /* MGLShape_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 408AA85A1DAEECF100022900 /* MGLShape_Private.h */; }; 408AA8651DAEEE3400022900 /* MGLPolygon+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 408AA8601DAEED3300022900 /* MGLPolygon+MGLAdditions.h */; }; 408AA8661DAEEE3600022900 /* MGLPolyline+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 408AA8611DAEED3300022900 /* MGLPolyline+MGLAdditions.h */; }; @@ -249,6 +251,8 @@ 35C5D84B1D6DD75B00E95907 /* MGLFilterTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFilterTests.mm; sourceTree = ""; }; 35D65C581D65AD5500722C23 /* NSDate+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+MGLAdditions.h"; sourceTree = ""; }; 35D65C591D65AD5500722C23 /* NSDate+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSDate+MGLAdditions.mm"; sourceTree = ""; }; + 4049C2A11DB6CE7800B3F799 /* MGLPointCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPointCollection.h; sourceTree = ""; }; + 4049C2A71DB6D09B00B3F799 /* MGLPointCollection.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLPointCollection.mm; sourceTree = ""; }; 405C03961DB0004E001AC280 /* NSImage+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSImage+MGLAdditions.h"; sourceTree = ""; }; 405C03971DB0004E001AC280 /* NSImage+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSImage+MGLAdditions.mm"; sourceTree = ""; }; 408AA85A1DAEECF100022900 /* MGLShape_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShape_Private.h; sourceTree = ""; }; @@ -665,24 +669,26 @@ isa = PBXGroup; children = ( DAE6C34B1CC31E0400DB3429 /* MGLAnnotation.h */, - DACC22121CF3D3E200D220D9 /* MGLFeature.h */, DACC22171CF3D4F700D220D9 /* MGLFeature_Private.h */, + DACC22121CF3D3E200D220D9 /* MGLFeature.h */, DACC22131CF3D3E200D220D9 /* MGLFeature.mm */, - DAE6C34C1CC31E0400DB3429 /* MGLGeometry.h */, DAE6C36C1CC31E2A00DB3429 /* MGLGeometry_Private.h */, + DAE6C34C1CC31E0400DB3429 /* MGLGeometry.h */, DAE6C36D1CC31E2A00DB3429 /* MGLGeometry.mm */, - DAE6C34E1CC31E0400DB3429 /* MGLMultiPoint.h */, DAE6C36F1CC31E2A00DB3429 /* MGLMultiPoint_Private.h */, + DAE6C34E1CC31E0400DB3429 /* MGLMultiPoint.h */, DAE6C3701CC31E2A00DB3429 /* MGLMultiPoint.mm */, DAE6C3521CC31E0400DB3429 /* MGLOverlay.h */, DAE6C3531CC31E0400DB3429 /* MGLPointAnnotation.h */, DAE6C3761CC31E2A00DB3429 /* MGLPointAnnotation.mm */, + 4049C2A11DB6CE7800B3F799 /* MGLPointCollection.h */, + 4049C2A71DB6D09B00B3F799 /* MGLPointCollection.mm */, DAE6C3541CC31E0400DB3429 /* MGLPolygon.h */, DAE6C3771CC31E2A00DB3429 /* MGLPolygon.mm */, DAE6C3551CC31E0400DB3429 /* MGLPolyline.h */, DAE6C3781CC31E2A00DB3429 /* MGLPolyline.mm */, - DAE6C3561CC31E0400DB3429 /* MGLShape.h */, 408AA85A1DAEECF100022900 /* MGLShape_Private.h */, + DAE6C3561CC31E0400DB3429 /* MGLShape.h */, DAE6C3791CC31E2A00DB3429 /* MGLShape.mm */, DAD165721CF4CD7A001FF4B9 /* MGLShapeCollection.h */, DAD165731CF4CD7A001FF4B9 /* MGLShapeCollection.m */, @@ -889,6 +895,7 @@ DAE6C3691CC31E0400DB3429 /* MGLTypes.h in Headers */, DAE6C3991CC31E2A00DB3429 /* NSException+MGLAdditions.h in Headers */, DA8F25871D51C9E10010E6B5 /* MGLBackgroundStyleLayer.h in Headers */, + 4049C2A51DB6CE7F00B3F799 /* MGLPointCollection.h in Headers */, 30E5781B1DAA857E0050F07E /* NSImage+MGLAdditions.h in Headers */, DAE6C3661CC31E0400DB3429 /* MGLShape.h in Headers */, DA551B831DB496AC0009AFAF /* MGLTileSet_Private.h in Headers */, @@ -1146,6 +1153,7 @@ DAE6C3BA1CC31EF300DB3429 /* MGLOpenGLLayer.mm in Sources */, DAE6C38A1CC31E2A00DB3429 /* MGLMultiPoint.mm in Sources */, DAE6C3961CC31E2A00DB3429 /* MGLTypes.m in Sources */, + 4049C2AD1DB8020600B3F799 /* MGLPointCollection.mm in Sources */, DA35A2A61CC9EB2700E826B2 /* MGLCoordinateFormatter.m in Sources */, 352742821D4C243B00A1ECE6 /* MGLSource.mm in Sources */, DAE6C3881CC31E2A00DB3429 /* MGLMapCamera.mm in Sources */, diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index a8f91a24e..81f9e249b 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -1645,12 +1645,6 @@ public: NSAssert([annotation conformsToProtocol:@protocol(MGLAnnotation)], @"Annotation does not conform to MGLAnnotation"); if ([annotation isKindOfClass:[MGLMultiPoint class]]) { - // Actual multipoints aren’t supported as annotations. - if ([annotation isMemberOfClass:[MGLMultiPoint class]] - || [annotation isMemberOfClass:[MGLMultiPointFeature class]]) { - continue; - } - // The multipoint knows how to style itself (with the map view’s help). MGLMultiPoint *multiPoint = (MGLMultiPoint *)annotation; if (!multiPoint.pointCount) { @@ -1664,8 +1658,9 @@ public: [(NSObject *)annotation addObserver:self forKeyPath:@"coordinates" options:0 context:(void *)(NSUInteger)annotationTag]; } else if (![annotation isKindOfClass:[MGLMultiPolyline class]] - || ![annotation isKindOfClass:[MGLMultiPolygon class]] - || ![annotation isKindOfClass:[MGLShapeCollection class]]) { + && ![annotation isKindOfClass:[MGLMultiPolygon class]] + && ![annotation isKindOfClass:[MGLShapeCollection class]] + && ![annotation isKindOfClass:[MGLPointCollection class]]) { MGLAnnotationImage *annotationImage = nil; if (delegateHasImagesForAnnotations) { annotationImage = [self.delegate mapView:self imageForAnnotation:annotation]; diff --git a/platform/macos/src/Mapbox.h b/platform/macos/src/Mapbox.h index 67e377510..cfddfe6e8 100644 --- a/platform/macos/src/Mapbox.h +++ b/platform/macos/src/Mapbox.h @@ -24,6 +24,7 @@ FOUNDATION_EXPORT const unsigned char MapboxVersionString[]; #import "MGLOfflineStorage.h" #import "MGLOverlay.h" #import "MGLPointAnnotation.h" +#import "MGLPointCollection.h" #import "MGLPolygon.h" #import "MGLPolyline.h" #import "MGLShape.h" From dc884cd6c30ecb8121996d2d22ccba77bf039df6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 26 Oct 2016 00:36:23 -0700 Subject: [PATCH 06/25] [ios, macos] Fixed syntax error in documentation comment (#6822) Fixes #6821. --- platform/darwin/scripts/generate-style-code.js | 3 +++ platform/darwin/src/MGLSymbolStyleLayer.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js index 4bcfe54d3..62ab3b6b9 100644 --- a/platform/darwin/scripts/generate-style-code.js +++ b/platform/darwin/scripts/generate-style-code.js @@ -152,6 +152,9 @@ global.describeValue = function (value, property, layerType) { case 'number': return 'an `NSNumber` object containing the float `' + value + '`'; case 'string': + if (value === '') { + return 'the empty string'; + } return 'the string `' + value + '`'; case 'enum': let displayValue; diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h index 3fcecedca..9bd943a34 100644 --- a/platform/darwin/src/MGLSymbolStyleLayer.h +++ b/platform/darwin/src/MGLSymbolStyleLayer.h @@ -388,7 +388,7 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { /** Value to use for a text label. Feature properties are specified using tokens like {field_name}. - The default value of this property is an `MGLStyleValue` object containing the string ``. Set this property to `nil` to reset it to the default value. + The default value of this property is an `MGLStyleValue` object containing the empty string. Set this property to `nil` to reset it to the default value. */ @property (nonatomic, null_resettable) MGLStyleValue *textField; From 62647a013ff398c28c8a2c2f37c2737006181302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Tue, 25 Oct 2016 23:22:34 -0700 Subject: [PATCH 07/25] [ios, macos] Corrected MGLStyleValue inheritance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MGLStyleConstantValue and MGLStyleFunction now inherit from MGLStyleValue with a generic argument matching the child class’s own generic argument. Fixes #6823. --- platform/darwin/src/MGLStyleValue.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/darwin/src/MGLStyleValue.h b/platform/darwin/src/MGLStyleValue.h index eb0eaf534..ab5e76bbe 100644 --- a/platform/darwin/src/MGLStyleValue.h +++ b/platform/darwin/src/MGLStyleValue.h @@ -68,7 +68,7 @@ NS_ASSUME_NONNULL_BEGIN The `MGLStyleConstantValue` class takes a generic parameter `T` that indicates the Foundation class being wrapped by this class. */ -@interface MGLStyleConstantValue : MGLStyleValue +@interface MGLStyleConstantValue : MGLStyleValue #pragma mark Creating a Style Constant Value @@ -111,7 +111,7 @@ NS_ASSUME_NONNULL_BEGIN The `MGLStyleFunction` class takes a generic parameter `T` that indicates the Foundation class being wrapped by this class. */ -@interface MGLStyleFunction : MGLStyleValue +@interface MGLStyleFunction : MGLStyleValue #pragma mark Creating a Style Function From 12093c10ad7557a92c8852bd6b61428990311dd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Tue, 25 Oct 2016 23:23:11 -0700 Subject: [PATCH 08/25] [ios, macos] Added Swift MGLStyleValue tests Added tests of MGLStyleValue written in Swift, along with bridging headers just in case they become needed in the future. --- platform/darwin/test/MGLStyleValueTests.swift | 36 +++++++++++++++++++ platform/darwin/test/test-Bridging-Header.h | 3 ++ platform/ios/ios.xcodeproj/project.pbxproj | 14 ++++++++ platform/ios/test/test-Bridging-Header.h | 3 ++ .../macos/macos.xcodeproj/project.pbxproj | 14 ++++++++ 5 files changed, 70 insertions(+) create mode 100644 platform/darwin/test/MGLStyleValueTests.swift create mode 100644 platform/darwin/test/test-Bridging-Header.h create mode 100644 platform/ios/test/test-Bridging-Header.h diff --git a/platform/darwin/test/MGLStyleValueTests.swift b/platform/darwin/test/MGLStyleValueTests.swift new file mode 100644 index 000000000..f7bf34385 --- /dev/null +++ b/platform/darwin/test/MGLStyleValueTests.swift @@ -0,0 +1,36 @@ +import XCTest +import Mapbox + +class MGLStyleValueTests: XCTestCase { + func testConstantValues() { + let geoJSONSource = MGLGeoJSONSource(identifier: "test", features: [], options: nil) + let symbolStyleLayer = MGLSymbolStyleLayer(identifier: "test", source: geoJSONSource) + + // Boolean + symbolStyleLayer.iconAllowOverlap = MGLStyleConstantValue(rawValue: true) + XCTAssertEqual((symbolStyleLayer.iconAllowOverlap as! MGLStyleConstantValue).rawValue, true) + + // Number + symbolStyleLayer.iconHaloWidth = MGLStyleConstantValue(rawValue: 3) + XCTAssertEqual((symbolStyleLayer.iconHaloWidth as! MGLStyleConstantValue).rawValue, 3) + + // String + symbolStyleLayer.textField = MGLStyleConstantValue(rawValue: "{name}") + XCTAssertEqual((symbolStyleLayer.textField as! MGLStyleConstantValue).rawValue, "{name}") + } + + func testFunctions() { + let geoJSONSource = MGLGeoJSONSource(identifier: "test", features: [], options: nil) + let symbolStyleLayer = MGLSymbolStyleLayer(identifier: "test", source: geoJSONSource) + + // Boolean + let stops: [NSNumber: MGLStyleValue] = [ + 1: MGLStyleValue(rawValue: true), + 2: MGLStyleValue(rawValue: false), + 3: MGLStyleValue(rawValue: true), + 4: MGLStyleValue(rawValue: false), + ] + symbolStyleLayer.iconAllowOverlap = MGLStyleFunction(base: 1, stops: stops) + XCTAssertEqual((symbolStyleLayer.iconAllowOverlap as! MGLStyleFunction), MGLStyleFunction(base: 1, stops: stops)) + } +} diff --git a/platform/darwin/test/test-Bridging-Header.h b/platform/darwin/test/test-Bridging-Header.h new file mode 100644 index 000000000..e11d920b1 --- /dev/null +++ b/platform/darwin/test/test-Bridging-Header.h @@ -0,0 +1,3 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index 825377476..48be68275 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -174,6 +174,7 @@ DA1DC99B1CB6E064006E619F /* MBXViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DA1DC99A1CB6E064006E619F /* MBXViewController.m */; }; DA1DC99D1CB6E076006E619F /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA1DC99C1CB6E076006E619F /* Default-568h@2x.png */; }; DA1DC99F1CB6E088006E619F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA1DC99E1CB6E088006E619F /* Assets.xcassets */; }; + DA2207BF1DC0805F0002F84D /* MGLStyleValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2207BE1DC0805F0002F84D /* MGLStyleValueTests.swift */; }; DA25D5C01CCD9F8400607828 /* Root.plist in Resources */ = {isa = PBXBuildFile; fileRef = DA25D5BF1CCD9F8400607828 /* Root.plist */; }; DA25D5C61CCDA06800607828 /* Root.strings in Resources */ = {isa = PBXBuildFile; fileRef = DA25D5C41CCDA06800607828 /* Root.strings */; }; DA25D5CD1CCDA11500607828 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = DA25D5B91CCD9EDE00607828 /* Settings.bundle */; }; @@ -601,6 +602,8 @@ DA1DC99A1CB6E064006E619F /* MBXViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBXViewController.m; sourceTree = ""; }; DA1DC99C1CB6E076006E619F /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; DA1DC99E1CB6E088006E619F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + DA2207BD1DC0805F0002F84D /* test-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "test-Bridging-Header.h"; sourceTree = ""; }; + DA2207BE1DC0805F0002F84D /* MGLStyleValueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MGLStyleValueTests.swift; path = ../../darwin/test/MGLStyleValueTests.swift; sourceTree = ""; }; DA25D5B91CCD9EDE00607828 /* Settings.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Settings.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; DA25D5BF1CCD9F8400607828 /* Root.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Root.plist; sourceTree = ""; }; DA25D5C51CCDA06800607828 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Root.strings; sourceTree = ""; }; @@ -885,9 +888,11 @@ 357579811D502AD4000B822E /* Styling */ = { isa = PBXGroup; children = ( + DA2207BD1DC0805F0002F84D /* test-Bridging-Header.h */, 3575798F1D513EF1000B822E /* Layers */, 35B8E08B1D6C8B5100E768D2 /* MGLFilterTests.mm */, 40CFA64E1D78754A008103BD /* Sources */, + DA2207BE1DC0805F0002F84D /* MGLStyleValueTests.swift */, ); name = Styling; sourceTree = ""; @@ -1713,6 +1718,7 @@ }; DA2E88501CC036F400F24E7B = { CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 0800; }; DA8847D11CBAF91600AB86E3 = { CreatedOnToolsVersion = 7.3; @@ -1882,6 +1888,7 @@ 357579851D502AF5000B822E /* MGLSymbolStyleLayerTests.m in Sources */, 357579871D502AFE000B822E /* MGLLineStyleLayerTests.m in Sources */, 357579891D502B06000B822E /* MGLCircleStyleLayerTests.m in Sources */, + DA2207BF1DC0805F0002F84D /* MGLStyleValueTests.swift in Sources */, 40CFA6511D7875BB008103BD /* MGLGeoJSONSourceTests.mm in Sources */, DA35A2C51CCA9F8300E826B2 /* MGLClockDirectionFormatterTests.m in Sources */, 35B8E08C1D6C8B5100E768D2 /* MGLFilterTests.mm in Sources */, @@ -2280,6 +2287,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 55D8C9941D0F133500F42F10 /* config.xcconfig */; buildSettings = { + CLANG_ENABLE_MODULES = YES; HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)"; INFOPLIST_FILE = test/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; @@ -2292,6 +2300,9 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "test/test-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -2299,6 +2310,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 55D8C9941D0F133500F42F10 /* config.xcconfig */; buildSettings = { + CLANG_ENABLE_MODULES = YES; HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)"; INFOPLIST_FILE = test/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; @@ -2311,6 +2323,8 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "test/test-Bridging-Header.h"; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/platform/ios/test/test-Bridging-Header.h b/platform/ios/test/test-Bridging-Header.h new file mode 100644 index 000000000..e11d920b1 --- /dev/null +++ b/platform/ios/test/test-Bridging-Header.h @@ -0,0 +1,3 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj index 9c610a820..0194a2e6c 100644 --- a/platform/macos/macos.xcodeproj/project.pbxproj +++ b/platform/macos/macos.xcodeproj/project.pbxproj @@ -57,6 +57,7 @@ 558F18221D0B13B100123F46 /* libmbgl-loop.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 558F18211D0B13B000123F46 /* libmbgl-loop.a */; }; 55D9B4B11D005D3900C1CCE2 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 55D9B4B01D005D3900C1CCE2 /* libz.tbd */; }; DA0CD58E1CF56F5800A5F5A5 /* MGLFeatureTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA0CD58D1CF56F5800A5F5A5 /* MGLFeatureTests.mm */; }; + DA2207BC1DC076940002F84D /* MGLStyleValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2207BB1DC076940002F84D /* MGLStyleValueTests.swift */; }; DA2DBBCB1D51E30A00D38FF9 /* MGLStyleLayerTests.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA2DBBCA1D51E30A00D38FF9 /* MGLStyleLayerTests.xib */; }; 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 */; }; @@ -271,6 +272,8 @@ 55D9B4B01D005D3900C1CCE2 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 55FE0E8D1D100A0900FD240B /* config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = config.xcconfig; path = ../../build/macos/config.xcconfig; sourceTree = ""; }; DA0CD58D1CF56F5800A5F5A5 /* MGLFeatureTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLFeatureTests.mm; path = ../../darwin/test/MGLFeatureTests.mm; sourceTree = ""; }; + DA2207BA1DC076930002F84D /* test-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "test-Bridging-Header.h"; sourceTree = ""; }; + DA2207BB1DC076940002F84D /* MGLStyleValueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MGLStyleValueTests.swift; sourceTree = ""; }; DA2DBBC71D51E26600D38FF9 /* MGLStyleLayerTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGLStyleLayerTests.h; path = ../darwin/test/MGLStyleLayerTests.h; sourceTree = SOURCE_ROOT; }; DA2DBBC81D51E26600D38FF9 /* MGLStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLStyleLayerTests.m; path = ../darwin/test/MGLStyleLayerTests.m; sourceTree = SOURCE_ROOT; }; DA2DBBCA1D51E30A00D38FF9 /* MGLStyleLayerTests.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MGLStyleLayerTests.xib; sourceTree = ""; }; @@ -605,6 +608,7 @@ DA8F257C1D51C5F40010E6B5 /* Layers */ = { isa = PBXGroup; children = ( + DA2207BA1DC076930002F84D /* test-Bridging-Header.h */, DA2DBBC71D51E26600D38FF9 /* MGLStyleLayerTests.h */, DA2DBBC81D51E26600D38FF9 /* MGLStyleLayerTests.m */, DA8F25741D51C5F40010E6B5 /* MGLFillStyleLayerTests.m */, @@ -616,6 +620,7 @@ DA8F257A1D51C5F40010E6B5 /* MGLRuntimeStylingHelper.h */, DA8F257B1D51C5F40010E6B5 /* MGLRuntimeStylingHelper.m */, DA2DBBCA1D51E30A00D38FF9 /* MGLStyleLayerTests.xib */, + DA2207BB1DC076940002F84D /* MGLStyleValueTests.swift */, ); name = Layers; sourceTree = ""; @@ -1041,6 +1046,7 @@ }; DAE6C3301CC30DB200DB3429 = { CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 0800; }; }; }; @@ -1197,6 +1203,7 @@ DAE6C3D31CC34C9900DB3429 /* MGLOfflinePackTests.m in Sources */, DA35A2A81CC9F41600E826B2 /* MGLCoordinateFormatterTests.m in Sources */, DA0CD58E1CF56F5800A5F5A5 /* MGLFeatureTests.mm in Sources */, + DA2207BC1DC076940002F84D /* MGLStyleValueTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1465,6 +1472,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 55FE0E8D1D100A0900FD240B /* config.xcconfig */; buildSettings = { + CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)"; INFOPLIST_FILE = test/Info.plist; @@ -1477,6 +1485,9 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "../darwin/test/test-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -1484,6 +1495,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 55FE0E8D1D100A0900FD240B /* config.xcconfig */; buildSettings = { + CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)"; INFOPLIST_FILE = test/Info.plist; @@ -1496,6 +1508,8 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "../darwin/test/test-Bridging-Header.h"; + SWIFT_VERSION = 3.0; }; name = Release; }; From 67ffc9685e573b10e4761b0bdb9962c79139f5da Mon Sep 17 00:00:00 2001 From: Jesse Bounds Date: Wed, 26 Oct 2016 17:08:27 -0700 Subject: [PATCH 09/25] [ios, macos] Make source ownership consistent and GeoJSON content properties writable Use common initialization logic to create an unique pointer to an mbgl source object, up front, when a MGL source is created. Keep a raw pointer to the unique pointer that is pointed at the mbgl source instance when a MGL source is created or when a MGL source is obtained by identifier from MGLStyle. Once the transfer of ownership of the mbgl source takes place, the unique ptr is null. The raw pointer can be used internally for future work that involves mutating the source. This also changes the URL, features, and geoJSONData content properties for MGLGeoJSON source to be writable. If they are set with valid data after a source has been added to the map then the map will update to reflect the new data. --- platform/darwin/src/MGLGeoJSONSource.h | 6 +- platform/darwin/src/MGLGeoJSONSource.mm | 105 +++++++++++--- .../darwin/src/MGLGeoJSONSource_Private.h | 1 + platform/darwin/src/MGLRasterSource.mm | 23 ++- platform/darwin/src/MGLSource.mm | 17 +-- platform/darwin/src/MGLSource_Private.h | 23 ++- platform/darwin/src/MGLStyle.mm | 12 +- platform/darwin/src/MGLVectorSource.mm | 22 ++- platform/ios/app/Info.plist | 13 ++ platform/ios/app/MBXViewController.m | 136 ++++++++++++++++++ platform/ios/test/MGLGeoJSONSourceTests.mm | 27 +--- 11 files changed, 313 insertions(+), 72 deletions(-) diff --git a/platform/darwin/src/MGLGeoJSONSource.h b/platform/darwin/src/MGLGeoJSONSource.h index 9eeb1e118..d0c1e0dc6 100644 --- a/platform/darwin/src/MGLGeoJSONSource.h +++ b/platform/darwin/src/MGLGeoJSONSource.h @@ -109,7 +109,7 @@ extern NSString * const MGLGeoJSONToleranceOption; is set to `nil`. This property is unavailable until the receiver is passed into `-[MGLStyle addSource]`. */ -@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id ) *features; +@property (nonatomic, nullable) NS_ARRAY_OF(id ) *features; /** A GeoJSON representation of the contents of the source. @@ -123,7 +123,7 @@ extern NSString * const MGLGeoJSONToleranceOption; This property is unavailable until the receiver is passed into `-[MGLStyle addSource]`. */ -@property (nonatomic, readonly, nullable, copy) NSData *geoJSONData; +@property (nonatomic, nullable, copy) NSData *geoJSONData; /** The URL to the GeoJSON document that specifies the contents of the source. @@ -131,7 +131,7 @@ extern NSString * const MGLGeoJSONToleranceOption; If the receiver was initialized using `-initWithIdentifier:geoJSONData:options`, this property is set to `nil`. */ -@property (nonatomic, readonly, nullable) NSURL *URL; +@property (nonatomic, nullable) NSURL *URL; @end diff --git a/platform/darwin/src/MGLGeoJSONSource.mm b/platform/darwin/src/MGLGeoJSONSource.mm index 27f2eb8bd..3efcd59ae 100644 --- a/platform/darwin/src/MGLGeoJSONSource.mm +++ b/platform/darwin/src/MGLGeoJSONSource.mm @@ -1,5 +1,6 @@ -#import "MGLGeoJSONSource.h" +#import "MGLGeoJSONSource_Private.h" +#import "MGLMapView_Private.h" #import "MGLSource_Private.h" #import "MGLFeature_Private.h" @@ -7,6 +8,7 @@ #include + NSString * const MGLGeoJSONClusterOption = @"MGLGeoJSONCluster"; NSString * const MGLGeoJSONClusterRadiusOption = @"MGLGeoJSONClusterRadius"; NSString * const MGLGeoJSONClusterMaximumZoomLevelOption = @"MGLGeoJSONClusterMaximumZoomLevel"; @@ -17,10 +19,14 @@ NSString * const MGLGeoJSONToleranceOption = @"MGLGeoJSONOptionsClusterTolerance @interface MGLGeoJSONSource () @property (nonatomic, readwrite) NSDictionary *options; +@property (nonatomic) mbgl::style::GeoJSONSource *rawSource; @end @implementation MGLGeoJSONSource +{ + std::unique_ptr _pendingSource; +} - (instancetype)initWithIdentifier:(NSString *)identifier geoJSONData:(NSData *)data options:(NS_DICTIONARY_OF(NSString *, id) *)options { @@ -28,6 +34,7 @@ NSString * const MGLGeoJSONToleranceOption = @"MGLGeoJSONOptionsClusterTolerance { _geoJSONData = data; _options = options; + [self commonInit]; } return self; } @@ -38,6 +45,7 @@ NSString * const MGLGeoJSONToleranceOption = @"MGLGeoJSONOptionsClusterTolerance { _URL = url; _options = options; + [self commonInit]; } return self; } @@ -46,11 +54,45 @@ NSString * const MGLGeoJSONToleranceOption = @"MGLGeoJSONOptionsClusterTolerance if (self = [super initWithIdentifier:identifier]) { _features = features; _options = options; + [self commonInit]; } return self; } +- (void)addToMapView:(MGLMapView *)mapView +{ + mapView.mbglMap->addSource(std::move(_pendingSource)); +} + +- (void)commonInit +{ + auto source = std::make_unique(self.identifier.UTF8String, self.geoJSONOptions); + + if (self.URL) { + NSURL *url = self.URL.mgl_URLByStandardizingScheme; + source->setURL(url.absoluteString.UTF8String); + _features = nil; + } else if (self.geoJSONData) { + NSString *string = [[NSString alloc] initWithData:self.geoJSONData encoding:NSUTF8StringEncoding]; + const auto geojson = mapbox::geojson::parse(string.UTF8String).get(); + source->setGeoJSON(geojson); + _features = MGLFeaturesFromMBGLFeatures(geojson); + } else { + mbgl::FeatureCollection featureCollection; + featureCollection.reserve(self.features.count); + for (id feature in self.features) { + featureCollection.push_back([feature mbglFeature]); + } + const auto geojson = mbgl::GeoJSON{featureCollection}; + source->setGeoJSON(geojson); + _features = MGLFeaturesFromMBGLFeatures(featureCollection); + } + + _pendingSource = std::move(source); + self.rawSource = _pendingSource.get(); +} + - (mbgl::style::GeoJSONOptions)geoJSONOptions { auto mbglOptions = mbgl::style::GeoJSONOptions(); @@ -102,30 +144,51 @@ NSString * const MGLGeoJSONToleranceOption = @"MGLGeoJSONOptionsClusterTolerance } } -- (std::unique_ptr)mbglSource +- (void)setGeoJSONData:(NSData *)geoJSONData { - auto source = std::make_unique(self.identifier.UTF8String, self.geoJSONOptions); + _geoJSONData = geoJSONData; - if (self.URL) { - NSURL *url = self.URL.mgl_URLByStandardizingScheme; - source->setURL(url.absoluteString.UTF8String); - } else if (self.geoJSONData) { - NSString *string = [[NSString alloc] initWithData:self.geoJSONData encoding:NSUTF8StringEncoding]; - const auto geojson = mapbox::geojson::parse(string.UTF8String).get(); - source->setGeoJSON(geojson); - _features = MGLFeaturesFromMBGLFeatures(geojson); - } else { - mbgl::FeatureCollection featureCollection; - featureCollection.reserve(self.features.count); - for (id feature in self.features) { - featureCollection.push_back([feature mbglFeature]); - } - const auto geojson = mbgl::GeoJSON{featureCollection}; - source->setGeoJSON(geojson); - _features = MGLFeaturesFromMBGLFeatures(featureCollection); + if (self.rawSource == NULL) + { + [self commonInit]; } - return std::move(source); + NSString *string = [[NSString alloc] initWithData:_geoJSONData encoding:NSUTF8StringEncoding]; + const auto geojson = mapbox::geojson::parse(string.UTF8String).get(); + self.rawSource->setGeoJSON(geojson); + + _features = MGLFeaturesFromMBGLFeatures(geojson); +} + +- (void)setURL:(NSURL *)URL +{ + _URL = URL; + + if (self.rawSource == NULL) + { + [self commonInit]; + } + + NSURL *url = self.URL.mgl_URLByStandardizingScheme; + self.rawSource->setURL(url.absoluteString.UTF8String); +} + +- (void)setFeatures:(NSArray *)features +{ + if (self.rawSource == NULL) + { + [self commonInit]; + } + + mbgl::FeatureCollection featureCollection; + featureCollection.reserve(features.count); + for (id feature in features) { + featureCollection.push_back([feature mbglFeature]); + } + const auto geojson = mbgl::GeoJSON{featureCollection}; + self.rawSource->setGeoJSON(geojson); + + _features = MGLFeaturesFromMBGLFeatures(featureCollection); } @end diff --git a/platform/darwin/src/MGLGeoJSONSource_Private.h b/platform/darwin/src/MGLGeoJSONSource_Private.h index 3aeb07ad2..de5bb10fa 100644 --- a/platform/darwin/src/MGLGeoJSONSource_Private.h +++ b/platform/darwin/src/MGLGeoJSONSource_Private.h @@ -1,3 +1,4 @@ +#import "MGLGeoJSONSource.h" #import "MGLGeoJSONSource_Private.h" #include diff --git a/platform/darwin/src/MGLRasterSource.mm b/platform/darwin/src/MGLRasterSource.mm index 41b9a5b04..fc47c2385 100644 --- a/platform/darwin/src/MGLRasterSource.mm +++ b/platform/darwin/src/MGLRasterSource.mm @@ -1,18 +1,29 @@ #import "MGLRasterSource.h" +#import "MGLMapView_Private.h" #import "MGLSource_Private.h" #import "MGLTileSet_Private.h" #import "NSURL+MGLAdditions.h" #include +@interface MGLRasterSource () + +@property (nonatomic) mbgl::style::RasterSource *rawSource; + +@end + @implementation MGLRasterSource +{ + std::unique_ptr _pendingSource; +} - (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url tileSize:(CGFloat)tileSize { if (self = [super initWithIdentifier:identifier]) { _URL = url; _tileSize = tileSize; + [self commonInit]; } return self; } @@ -23,11 +34,12 @@ { _tileSet = tileSet; _tileSize = tileSize; + [self commonInit]; } return self; } -- (std::unique_ptr)mbglSource +- (void)commonInit { std::unique_ptr source; @@ -42,10 +54,15 @@ source = std::make_unique(self.identifier.UTF8String, self.tileSet.mbglTileset, uint16_t(self.tileSize)); - } - return std::move(source); + _pendingSource = std::move(source); + self.rawSource = _pendingSource.get(); +} + +- (void)addToMapView:(MGLMapView *)mapView +{ + mapView.mbglMap->addSource(std::move(_pendingSource)); } @end diff --git a/platform/darwin/src/MGLSource.mm b/platform/darwin/src/MGLSource.mm index 85bbc0634..1b889d44d 100644 --- a/platform/darwin/src/MGLSource.mm +++ b/platform/darwin/src/MGLSource.mm @@ -2,27 +2,14 @@ #include -@interface MGLSource () - -@property (nonatomic) mbgl::style::Source *source; - -@end - @implementation MGLSource -- (instancetype)initWithIdentifier:(NSString *)identifier { +- (instancetype)initWithIdentifier:(NSString *)identifier +{ if (self = [super init]) { _identifier = identifier; } return self; } -- (std::unique_ptr)mbglSource { - [NSException raise:@"MGLAbstractClassException" format: - @"The source %@ cannot be added to the style. " - @"Make sure the source was created as a member of a concrete subclass of MGLSource.", - NSStringFromClass(self)]; - return nil; -} - @end diff --git a/platform/darwin/src/MGLSource_Private.h b/platform/darwin/src/MGLSource_Private.h index 2b8658b4c..dff230ede 100644 --- a/platform/darwin/src/MGLSource_Private.h +++ b/platform/darwin/src/MGLSource_Private.h @@ -3,10 +3,29 @@ #include #include +@class MGLMapView; + @interface MGLSource (Private) -- (std::unique_ptr)mbglSource; +/** + A raw pointer to the mbgl object, which is always initialized, either to the + value returned by `mbgl::Map getSource`, or for independently created objects, + to the pointer value held in `pendingSource`. In the latter case, this raw + pointer value stays even after ownership of the object is transferred via + `mbgl::Map addSource`. + */ +@property (nonatomic) mbgl::style::Source *rawSource; -@property (nonatomic) mbgl::style::Source *source; +/** + Adds the mbgl source that this object represents to the mbgl map. + + Once a mbgl source is added, ownership of the object is transferred to the + `mbgl::Map` and this object no longer has an active unique_ptr reference to the + `mbgl::Source`. If this object's mbgl source is in that state, the mbgl source + can still be changed but the changes will not be visible until the `MGLSource` + is added back to the map via `-[MGLStyle addSource:]` and styled with a + `MGLLayer`. + */ +- (void)addToMapView:(MGLMapView *)mapView; @end diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm index 3964b47ad..a17b7d6b7 100644 --- a/platform/darwin/src/MGLStyle.mm +++ b/platform/darwin/src/MGLStyle.mm @@ -142,6 +142,7 @@ static NSURL *MGLStyleURL_emerald; - (MGLSource *)sourceWithIdentifier:(NSString *)identifier { auto mbglSource = self.mapView.mbglMap->getSource(identifier.UTF8String); + if (!mbglSource) { return nil; } @@ -159,8 +160,8 @@ static NSURL *MGLStyleURL_emerald; NSAssert(NO, @"Unrecognized source type"); return nil; } - - source.source = mbglSource; + + source.rawSource = mbglSource; return source; } @@ -205,12 +206,17 @@ static NSURL *MGLStyleURL_emerald; - (void)addSource:(MGLSource *)source { - self.mapView.mbglMap->addSource(source.mbglSource); + [source addToMapView:self.mapView]; } - (void)removeSource:(MGLSource *)source { self.mapView.mbglMap->removeSource(source.identifier.UTF8String); + + // Once a mbgl source is removed from the map, ownership does not return + // to the MGL source. Therefore, the rawSource pointer is set to NULL + // so that the implementation of MGL source can avoid using it again. + source.rawSource = NULL; } - (NS_ARRAY_OF(NSString *) *)styleClasses diff --git a/platform/darwin/src/MGLVectorSource.mm b/platform/darwin/src/MGLVectorSource.mm index 359781235..995565419 100644 --- a/platform/darwin/src/MGLVectorSource.mm +++ b/platform/darwin/src/MGLVectorSource.mm @@ -1,12 +1,22 @@ #import "MGLVectorSource.h" +#import "MGLMapView_Private.h" #import "MGLSource_Private.h" #import "MGLTileSet_Private.h" #import "NSURL+MGLAdditions.h" #include +@interface MGLVectorSource () + +@property (nonatomic) mbgl::style::VectorSource *rawSource; + +@end + @implementation MGLVectorSource +{ + std::unique_ptr _pendingSource; +} static NSString *MGLVectorSourceType = @"vector"; @@ -15,6 +25,7 @@ static NSString *MGLVectorSourceType = @"vector"; if (self = [super initWithIdentifier:identifier]) { _URL = url; + [self commonInit]; } return self; } @@ -24,11 +35,12 @@ static NSString *MGLVectorSourceType = @"vector"; if (self = [super initWithIdentifier:identifier]) { _tileSet = tileSet; + [self commonInit]; } return self; } -- (std::unique_ptr)mbglSource +- (void)commonInit { std::unique_ptr source; @@ -43,7 +55,13 @@ static NSString *MGLVectorSourceType = @"vector"; self.tileSet.mbglTileset); } - return std::move(source); + _pendingSource = std::move(source); + self.rawSource = _pendingSource.get(); +} + +- (void)addToMapView:(MGLMapView *)mapView +{ + mapView.mbglMap->addSource(std::move(_pendingSource)); } @end diff --git a/platform/ios/app/Info.plist b/platform/ios/app/Info.plist index 3602ab796..043bebc92 100644 --- a/platform/ios/app/Info.plist +++ b/platform/ios/app/Info.plist @@ -51,5 +51,18 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + NSAppTransportSecurity + + NSExceptionDomains + + stamen.com + + NSIncludesSubdomains + + NSTemporaryExceptionAllowsInsecureHTTPLoads + + + + diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index 3a58c1163..790ff307b 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -64,6 +64,11 @@ typedef NS_ENUM(NSInteger, MBXSettingsRuntimeStylingRows) { MBXSettingsRuntimeStylingStyleQuery, MBXSettingsRuntimeStylingFeatureSource, MBXSettingsRuntimeStylingPointCollection, + MBXSettingsRuntimeStylingUpdateGeoJSONSourceData, + MBXSettingsRuntimeStylingUpdateGeoJSONSourceURL, + MBXSettingsRuntimeStylingUpdateGeoJSONSourceFeatures, + MBXSettingsRuntimeStylingVectorSource, + MBXSettingsRuntimeStylingRasterSource, }; typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { @@ -310,6 +315,11 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { @"Style Query For GeoJSON", @"Style Feature", @"Style Dynamic Point Collection", + @"Update GeoJSON Source: Data", + @"Update GeoJSON Source: URL", + @"Update GeoJSON Source: Features", + @"Style Vector Source", + @"Style Raster Source", ]]; break; case MBXSettingsMiscellaneous: @@ -444,6 +454,21 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { case MBXSettingsRuntimeStylingPointCollection: [self styleDynamicPointCollection]; break; + case MBXSettingsRuntimeStylingUpdateGeoJSONSourceURL: + [self updateGeoJSONSourceURL]; + break; + case MBXSettingsRuntimeStylingUpdateGeoJSONSourceData: + [self updateGeoJSONSourceData]; + break; + case MBXSettingsRuntimeStylingUpdateGeoJSONSourceFeatures: + [self updateGeoJSONSourceFeatures]; + break; + case MBXSettingsRuntimeStylingVectorSource: + [self styleVectorSource]; + break; + case MBXSettingsRuntimeStylingRasterSource: + [self styleRasterSource]; + break; default: NSAssert(NO, @"All runtime styling setting rows should be implemented"); break; @@ -891,6 +916,85 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { [self.mapView.style addLayer:layer]; } +- (void)updateGeoJSONSourceData +{ + [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(40.329795743702064, -107.75390625) zoomLevel:11 animated:NO]; + + NSString *geoJSON = @"{\"type\": \"FeatureCollection\",\"features\": [{\"type\": \"Feature\",\"properties\": {},\"geometry\": {\"type\": \"LineString\",\"coordinates\": [[-107.75390625,40.329795743702064],[-104.34814453125,37.64903402157866]]}}]}"; + + NSData *data = [geoJSON dataUsingEncoding:NSUTF8StringEncoding]; + MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"mutable-data-source-id" geoJSONData:data options:nil]; + [self.mapView.style addSource:source]; + + MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"mutable-data-layer-id" source:source]; + [self.mapView.style addLayer:layer]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + NSString *geoJSON = @"{\"type\": \"FeatureCollection\",\"features\": [{\"type\": \"Feature\",\"properties\": {},\"geometry\": {\"type\": \"LineString\",\"coordinates\": [[-107.75390625,40.329795743702064],[-109.34814453125,37.64903402157866]]}}]}"; + NSData *data = [geoJSON dataUsingEncoding:NSUTF8StringEncoding]; + + source.geoJSONData = data; + }); +} + +- (void)updateGeoJSONSourceURL +{ + [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(48.668731, -122.857151) zoomLevel:11 animated:NO]; + + NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"polyline" ofType:@"geojson"]; + NSURL *geoJSONURL = [NSURL fileURLWithPath:filePath]; + MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"mutable-data-source-url-id" URL:geoJSONURL options:nil]; + [self.mapView.style addSource:source]; + + MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"mutable-data-layer-url-id" source:source]; + [self.mapView.style addLayer:layer]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(41.563986787078704, -75.04843935793578) zoomLevel:8 animated:NO]; + + NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"threestates" ofType:@"geojson"]; + NSURL *geoJSONURL = [NSURL fileURLWithPath:filePath]; + + source.URL = geoJSONURL; + }); +} + +- (void)updateGeoJSONSourceFeatures +{ + [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(-41.1520, 288.6592) zoomLevel:10 animated:NO]; + + CLLocationCoordinate2D smallBox[] = { + {-41.14763798539186, 288.68019104003906}, + {-41.140915920129665, 288.68019104003906}, + {-41.140915920129665, 288.6887741088867}, + {-41.14763798539186, 288.6887741088867}, + {-41.14763798539186, 288.68019104003906} + }; + + CLLocationCoordinate2D largeBox[] = { + {-41.17710352162799, 288.67298126220703}, + {-41.13962313627545, 288.67298126220703}, + {-41.13962313627545, 288.7261962890625}, + {-41.17710352162799, 288.7261962890625}, + {-41.17710352162799, 288.67298126220703} + }; + + MGLPolygonFeature *smallBoxFeature = [MGLPolygonFeature polygonWithCoordinates:smallBox count:sizeof(smallBox)/sizeof(smallBox[0])]; + MGLPolygonFeature *largeBoxFeature = [MGLPolygonFeature polygonWithCoordinates:largeBox count:sizeof(largeBox)/sizeof(largeBox[0])]; + + MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"mutable-data-source-features-id" features:@[smallBoxFeature] options:nil]; + [self.mapView.style addSource:source]; + + MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"mutable-data-layer-features-id" source:source]; + MGLStyleValue *fillColor = [MGLStyleValue valueWithRawValue:[UIColor redColor]]; + layer.fillColor = fillColor; + [self.mapView.style addLayer:layer]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + source.features = @[largeBoxFeature]; + }); +} + - (void)styleDynamicPointCollection { [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(36.9979, -109.0441) zoomLevel:14 animated:NO]; @@ -908,6 +1012,38 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { [self.mapView.style addLayer:layer]; } +- (void)styleVectorSource +{ + NSURL *url = [[NSURL alloc] initWithString:@"mapbox://mapbox.mapbox-terrain-v2"]; + MGLVectorSource *vectorSource = [[MGLVectorSource alloc] initWithIdentifier:@"style-vector-source-id" URL:url]; + [self.mapView.style addSource:vectorSource]; + + MGLBackgroundStyleLayer *backgroundLayer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"style-vector-background-layer-id"]; + backgroundLayer.backgroundColor = [MGLStyleValue valueWithRawValue:[UIColor blackColor]]; + [self.mapView.style addLayer:backgroundLayer]; + + MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"style-vector-line-layer-id" source:vectorSource]; + lineLayer.sourceLayerIdentifier = @"contour"; + NSUInteger lineJoinValue = MGLLineJoinRound; + lineLayer.lineJoin = [MGLStyleValue valueWithRawValue:[NSValue value:&lineJoinValue withObjCType:@encode(MGLLineJoin)]]; + NSUInteger lineCapValue = MGLLineCapRound; + lineLayer.lineCap = [MGLStyleValue valueWithRawValue:[NSValue value:&lineCapValue withObjCType:@encode(MGLLineCap)]]; + lineLayer.lineColor = [MGLStyleValue valueWithRawValue:[UIColor greenColor]]; + + [self.mapView.style addLayer:lineLayer]; +} + +- (void)styleRasterSource +{ + // 3rd party raster source requires NSAppTransportSecurity exception for stamen.com + MGLTileSet *rasterTileSet = [[MGLTileSet alloc] initWithTileURLTemplates:@[@"http://a.tile.stamen.com/terrain-background/{z}/{x}/{y}.jpg"]]; + MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithIdentifier:@"style-raster-source-id" tileSet:rasterTileSet tileSize:256]; + [self.mapView.style addSource:rasterSource]; + + MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"style-raster-layer-id" source:rasterSource]; + [self.mapView.style addLayer:rasterLayer]; +} + - (IBAction)startWorldTour { _isTouringWorld = YES; diff --git a/platform/ios/test/MGLGeoJSONSourceTests.mm b/platform/ios/test/MGLGeoJSONSourceTests.mm index c885873f7..96431ad01 100644 --- a/platform/ios/test/MGLGeoJSONSourceTests.mm +++ b/platform/ios/test/MGLGeoJSONSourceTests.mm @@ -32,8 +32,7 @@ XCTAssertEqual(mbglOptions.tolerance, 0.42); options = @{MGLGeoJSONClusterOption: @"number 1"}; - source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" URL:url options:options]; - XCTAssertThrows([source geoJSONOptions]); + XCTAssertThrows([[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" URL:url options:options]); } - (void)testMGLGeoJSONSourceWithData { @@ -43,8 +42,6 @@ NSData *data = [geoJSON dataUsingEncoding:NSUTF8StringEncoding]; MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" geoJSONData:data options:nil]; - [source mbglSource]; - XCTAssertNotNil(source.features); XCTAssertEqual(source.features.count, 1); XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLPolylineFeature class]]); @@ -56,8 +53,6 @@ MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" features:@[polylineFeature] options:nil]; - std::unique_ptr mbglSource = [source mbglSource]; - XCTAssertNotNil(source.features); XCTAssertEqual(source.features.count, 1); XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLPolylineFeature class]]); @@ -95,8 +90,6 @@ MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" features:@[polygonFeature] options:nil]; - std::unique_ptr mbglSource = [source mbglSource]; - XCTAssertNotNil(source.features); XCTAssertEqual(source.features.count, 1); MGLPolygonFeature *expectedPolygonFeature = (MGLPolygonFeature *)source.features.firstObject; @@ -131,8 +124,7 @@ MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:5 interiorPolygons:@[polygon]]; MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" features:@[polygonFeature] options:nil]; - - std::unique_ptr mbglSource = [source mbglSource]; + XCTAssertNotNil(source.features); XCTAssertEqual(source.features.count, 1); @@ -148,8 +140,6 @@ MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" features:@[multiPolylineFeature] options:nil]; - std::unique_ptr mbglSource = [source mbglSource]; - XCTAssertNotNil(source.features); XCTAssertEqual(source.features.count, 1); XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLMultiPolylineFeature class]]); @@ -179,8 +169,6 @@ MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" features:@[multiPolygonFeature] options:nil]; - std::unique_ptr mbglSource = [source mbglSource]; - XCTAssertNotNil(source.features); XCTAssertEqual(source.features.count, 1); XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLMultiPolygonFeature class]]); @@ -193,8 +181,6 @@ MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"souce-id" features:@[pointFeature] options:nil]; - std::unique_ptr mbglSource = [source mbglSource]; - XCTAssertNotNil(source.features); XCTAssertEqual(source.features.count, 1); XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLPointFeature class]]); @@ -208,11 +194,8 @@ CLLocationCoordinate2DMake(100.0, 1.0), CLLocationCoordinate2DMake(100.0, 0.0)}; MGLPointCollectionFeature *pointCollectionFeature = [MGLPointCollectionFeature pointCollectionWithCoordinates:coordinates count:5]; -; MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"souce-id" features:@[pointCollectionFeature] options:nil]; - - std::unique_ptr mbglSource = [source mbglSource]; - + XCTAssertNotNil(source.features); XCTAssertEqual(source.features.count, 1); XCTAssertTrue([source.features.firstObject isMemberOfClass:[MGLPointCollectionFeature class]]); @@ -253,9 +236,7 @@ MGLShapeCollectionFeature *shapeCollectionFeature_1 = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[polygonFeature, polylineFeature, multiPolygonFeature, multiPolylineFeature, pointCollectionFeature, pointFeature, shapeCollectionFeature]]; - MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"" features:@[shapeCollectionFeature_1] options:nil]; - - XCTAssertThrowsSpecificNamed([source mbglSource], NSException, @"Method unavailable"); + XCTAssertThrowsSpecificNamed([[MGLGeoJSONSource alloc] initWithIdentifier:@"source-id" features:@[shapeCollectionFeature_1] options:nil], NSException, @"Method unavailable"); } @end From d5af9b680b6b72eea7cd149a4552bd20bb676353 Mon Sep 17 00:00:00 2001 From: Jesse Bounds Date: Wed, 26 Oct 2016 17:13:38 -0700 Subject: [PATCH 10/25] [ios, macos] Introduce visible annotations API (#6061) Add visibleAnnotations API to make it easier for clients of MGLMapView to query for all visible annotations in the map or all visible annotations in a subsection of the map. --- platform/ios/app/MBXViewController.m | 19 ++++++++++++++++++ platform/ios/src/MGLMapView.h | 21 ++++++++++++++++++++ platform/ios/src/MGLMapView.mm | 29 ++++++++++++++++++++++++++++ platform/macos/src/MGLMapView.h | 21 ++++++++++++++++++++ platform/macos/src/MGLMapView.mm | 29 ++++++++++++++++++++++++++++ 5 files changed, 119 insertions(+) diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index 790ff307b..74f8b5f28 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -46,6 +46,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsAnnotationsRows) { MBXSettingsAnnotations10000Sprites, MBXSettingsAnnotationsTestShapes, MBXSettingsAnnotationsCustomCallout, + MBXSettingsAnnotationsQueryAnnotations, MBXSettingsAnnotationsRemoveAnnotations, }; @@ -296,6 +297,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { @"Add 10,000 Sprites", @"Add Test Shapes", @"Add Point With Custom Callout", + @"Query Annotations", @"Remove Annotations", ]]; break; @@ -401,6 +403,9 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { case MBXSettingsAnnotationsCustomCallout: [self addAnnotationWithCustomCallout]; break; + case MBXSettingsAnnotationsQueryAnnotations: + [self testQueryPointAnnotations]; + break; case MBXSettingsAnnotationsRemoveAnnotations: [self.mapView removeAnnotations:self.mapView.annotations]; break; @@ -1091,6 +1096,20 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { self.mapView.userTrackingMode = MGLUserTrackingModeFollow; } +- (void)testQueryPointAnnotations { + NSNumber *visibleAnnotationCount = @(self.mapView.visibleAnnotations.count); + NSString *message; + if ([visibleAnnotationCount integerValue] == 1) { + message = [NSString stringWithFormat:@"There is %@ visible annotation.", visibleAnnotationCount]; + } else { + message = [NSString stringWithFormat:@"There are %@ visible annotations.", visibleAnnotationCount]; + } + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Visible Annotations" message:message preferredStyle:UIAlertControllerStyleAlert]; + [alertController addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleCancel handler:nil]]; + [self presentViewController:alertController animated:YES completion:nil]; +} + - (void)printTelemetryLogFile { NSString *fileContents = [NSString stringWithContentsOfFile:[self telemetryDebugLogFilePath] encoding:NSUTF8StringEncoding error:nil]; diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h index 5a89632db..e467495a4 100644 --- a/platform/ios/src/MGLMapView.h +++ b/platform/ios/src/MGLMapView.h @@ -892,6 +892,16 @@ IB_DESIGNABLE */ @property (nonatomic, readonly, nullable) NS_ARRAY_OF(id ) *annotations; +/** + The complete list of annotations associated with the receiver that are + currently visible. + + The objects in this array must adopt the `MGLAnnotation` protocol. If no + annotations are associated with the map view or if no annotations associated + with the map view are currently visible, the value of this property is `nil`. + */ +@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id ) *visibleAnnotations; + /** Adds an annotation to the map view. @@ -986,6 +996,17 @@ IB_DESIGNABLE */ - (nullable __kindof MGLAnnotationView *)dequeueReusableAnnotationViewWithIdentifier:(NSString *)identifier; +/** + Returns the list of annotations associated with the receiver that intersect with + the given rectangle. + + @param rect A rectangle expressed in the map view’s coordinate system. + @return An array of objects that adopt the `MGLAnnotation` protocol or `nil` if + no annotations associated with the map view are currently visible in the + rectangle. + */ +- (nullable NS_ARRAY_OF(id ) *)visibleAnnotationsInRect:(CGRect)rect; + #pragma mark Managing Annotation Selections /** diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index c6c0920f5..24a69e1d5 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -2811,6 +2811,35 @@ public: return [NSArray arrayWithObjects:&annotations[0] count:annotations.size()]; } +- (nullable NS_ARRAY_OF(id ) *)visibleAnnotations +{ + return [self visibleAnnotationsInRect:self.bounds]; +} + +- (nullable NS_ARRAY_OF(id ) *)visibleAnnotationsInRect:(CGRect)rect +{ + if (_annotationContextsByAnnotationTag.empty()) + { + return nil; + } + + std::vector annotationTags = [self annotationTagsInRect:rect]; + if (annotationTags.size()) + { + NSMutableArray *annotations = [NSMutableArray arrayWithCapacity:annotationTags.size()]; + + for (auto const& annotationTag: annotationTags) + { + MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag[annotationTag]; + [annotations addObject:annotationContext.annotation]; + } + + return [annotations copy]; + } + + return nil; +} + /// Returns the annotation assigned the given tag. Cheap. - (id )annotationWithTag:(MGLAnnotationTag)tag { diff --git a/platform/macos/src/MGLMapView.h b/platform/macos/src/MGLMapView.h index 3499671ff..3dbbbe3d8 100644 --- a/platform/macos/src/MGLMapView.h +++ b/platform/macos/src/MGLMapView.h @@ -568,6 +568,16 @@ IB_DESIGNABLE */ - (void)addAnnotations:(NS_ARRAY_OF(id ) *)annotations; +/** + The complete list of annotations associated with the receiver that are + currently visible. + + The objects in this array must adopt the `MGLAnnotation` protocol. If no + annotations are associated with the map view or if no annotations associated + with the map view are currently visible, the value of this property is `nil`. + */ +@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id ) *visibleAnnotations; + /** Removes an annotation from the map view, deselecting it if it is selected. @@ -608,6 +618,17 @@ IB_DESIGNABLE */ - (nullable MGLAnnotationImage *)dequeueReusableAnnotationImageWithIdentifier:(NSString *)identifier; +/** + Returns the list of annotations associated with the receiver that intersect with + the given rectangle. + + @param rect A rectangle expressed in the map view’s coordinate system. + @return An array of objects that adopt the `MGLAnnotation` protocol or `nil` if + no annotations associated with the map view are currently visible in the + rectangle. + */ +- (nullable NS_ARRAY_OF(id ) *)visibleAnnotationsInRect:(CGRect)rect; + #pragma mark Managing Annotation Selections /** diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index 14b83762a..4d1f00359 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -1616,6 +1616,35 @@ public: return [NSArray arrayWithObjects:&annotations[0] count:annotations.size()]; } +- (nullable NS_ARRAY_OF(id ) *)visibleAnnotations +{ + return [self visibleFeaturesInRect:self.bounds]; +} + +- (nullable NS_ARRAY_OF(id ) *)visibleAnnotationsInRect:(CGRect)rect +{ + if (_annotationContextsByAnnotationTag.empty()) + { + return nil; + } + + std::vector annotationTags = [self annotationTagsInRect:rect]; + if (annotationTags.size()) + { + NSMutableArray *annotations = [NSMutableArray arrayWithCapacity:annotationTags.size()]; + + for (auto const& annotationTag: annotationTags) + { + MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag[annotationTag]; + [annotations addObject:annotationContext.annotation]; + } + + return [annotations copy]; + } + + return nil; +} + /// Returns the annotation assigned the given tag. Cheap. - (id )annotationWithTag:(MGLAnnotationTag)tag { if (!_annotationContextsByAnnotationTag.count(tag)) { From 2242e5484cc81ef00b3cbf68d98dbcb8cdc16496 Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Tue, 25 Oct 2016 16:35:38 -0700 Subject: [PATCH 11/25] [ios] Add country label language toggle demo - Select best language based on locale setting and our support. --- platform/ios/app/MBXViewController.m | 75 +++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index 74f8b5f28..a5503f38e 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -70,6 +70,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsRuntimeStylingRows) { MBXSettingsRuntimeStylingUpdateGeoJSONSourceFeatures, MBXSettingsRuntimeStylingVectorSource, MBXSettingsRuntimeStylingRasterSource, + MBXSettingsRuntimeStylingCountryLabels, }; typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { @@ -105,6 +106,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { @property (nonatomic) NSInteger styleIndex; @property (nonatomic) BOOL debugLoggingEnabled; @property (nonatomic) BOOL customUserLocationAnnnotationEnabled; +@property (nonatomic) BOOL usingLocaleBasedCountryLabels; @end @@ -322,6 +324,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { @"Update GeoJSON Source: Features", @"Style Vector Source", @"Style Raster Source", + [NSString stringWithFormat:@"Label Countries in %@", (_usingLocaleBasedCountryLabels ? @"Local Language" : [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:[self bestLanguageForUser]])], ]]; break; case MBXSettingsMiscellaneous: @@ -474,6 +477,9 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { case MBXSettingsRuntimeStylingRasterSource: [self styleRasterSource]; break; + case MBXSettingsRuntimeStylingCountryLabels: + [self styleCountryLabelsLanguage]; + break; default: NSAssert(NO, @"All runtime styling setting rows should be implemented"); break; @@ -834,7 +840,6 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { }); } - - (void)styleQuery { CGRect queryRect = CGRectInset(self.mapView.bounds, 100, 200); @@ -1049,6 +1054,66 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { [self.mapView.style addLayer:rasterLayer]; } +-(void)styleCountryLabelsLanguage +{ + NSArray *labelLayers = @[ + @"country-label-lg", + @"country-label-md", + @"country-label-sm", + ]; + [self styleLabelLanguageForLayersNamed:labelLayers]; +} + +- (void)styleLabelLanguageForLayersNamed:(NSArray *)layers +{ + _usingLocaleBasedCountryLabels = !_usingLocaleBasedCountryLabels; + NSString *bestLanguageForUser = [NSString stringWithFormat:@"{name_%@}", [self bestLanguageForUser]]; + NSString *language = _usingLocaleBasedCountryLabels ? bestLanguageForUser : @"{name}"; + + for (NSString *layerName in layers) { + MGLSymbolStyleLayer *layer = (MGLSymbolStyleLayer *)[self.mapView.style layerWithIdentifier:layerName]; + + if ([layer isKindOfClass:[MGLSymbolStyleLayer class]]) { + if ([layer.textField isKindOfClass:[MGLStyleConstantValue class]]) { + MGLStyleConstantValue *label = (MGLStyleConstantValue *)layer.textField; + if ([label.rawValue hasPrefix:@"{name"]) { + layer.textField = [MGLStyleValue valueWithRawValue:language]; + } + } else if ([layer.textField isKindOfClass:[MGLStyleFunction class]]) { + MGLStyleFunction *function = (MGLStyleFunction *)layer.textField; + [function.stops enumerateKeysAndObjectsUsingBlock:^(id zoomLevel, id stop, BOOL *done) { + if ([stop isKindOfClass:[MGLStyleConstantValue class]]) { + MGLStyleConstantValue *label = (MGLStyleConstantValue *)stop; + if ([label.rawValue hasPrefix:@"{name"]) { + [function.stops setValue:[MGLStyleValue valueWithRawValue:language] forKey:zoomLevel]; + } + } + }]; + layer.textField = function; + } + } else { + NSLog(@"%@ is not a symbol style layer", layerName); + } + } +} + +- (NSString *)bestLanguageForUser +{ + NSArray *supportedLanguages = @[ @"en", @"es", @"fr", @"de", @"ru", @"zh" ]; + NSArray *preferredLanguages = [NSLocale preferredLanguages]; + NSString *bestLanguage; + + for (NSString *language in preferredLanguages) { + NSString *thisLanguage = [NSLocale localeWithLocaleIdentifier:language].languageCode; + if ([supportedLanguages containsObject:thisLanguage]) { + bestLanguage = thisLanguage; + break; + } + } + + return bestLanguage ?: @"en"; +} + - (IBAction)startWorldTour { _isTouringWorld = YES; @@ -1443,4 +1508,12 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { point.coordinate = [self.mapView convertPoint:self.mapView.center toCoordinateFromView:self.mapView]; } +- (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style +{ + // Default Mapbox styles use {name_en} as their label language, which means + // that a device with an English-language locale is already effectively + // using locale-based country labels. + _usingLocaleBasedCountryLabels = [[self bestLanguageForUser] isEqualToString:@"en"]; +} + @end From 300720c8c719f976b54a5c01edf816949f62918d Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Fri, 28 Oct 2016 14:43:25 -0700 Subject: [PATCH 12/25] [ios] Do iosapp token handling in viewDidLoad Doing this work in viewDidAppear meant that it happened every time the modal debug settings view disappeared (and the map view reappeared). --- platform/ios/app/MBXViewController.m | 5 ----- 1 file changed, 5 deletions(-) diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index a5503f38e..e8a78abff 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -140,12 +140,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { [self restoreState:nil]; self.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsDebugLoggingEnabled"]; -} -- (void)viewDidAppear:(BOOL)animated -{ - [super viewDidAppear:animated]; - if ([MGLAccountManager accessToken].length) { self.styleIndex = -1; From 8ffd1f69252d28bf501d5464ac9e5f6ff8942c89 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 31 Oct 2016 22:34:01 -0700 Subject: [PATCH 13/25] [ios, macos] document custom API URL & add Info.plist guide (#6833) Also support base URL nullability in order to use default value. --- platform/darwin/src/MGLNetworkConfiguration.h | 16 ++++++++++++-- platform/ios/CHANGELOG.md | 1 + platform/ios/docs/Info.plist Keys.md | 21 +++++++++++++++++++ platform/ios/scripts/document.sh | 1 + platform/macos/CHANGELOG.md | 1 + platform/macos/docs/Info.plist Keys.md | 17 +++++++++++++++ platform/macos/scripts/document.sh | 1 + 7 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 platform/ios/docs/Info.plist Keys.md create mode 100644 platform/macos/docs/Info.plist Keys.md diff --git a/platform/darwin/src/MGLNetworkConfiguration.h b/platform/darwin/src/MGLNetworkConfiguration.h index 4e22fa294..88fb07e11 100644 --- a/platform/darwin/src/MGLNetworkConfiguration.h +++ b/platform/darwin/src/MGLNetworkConfiguration.h @@ -1,11 +1,23 @@ #import +NS_ASSUME_NONNULL_BEGIN + +/** + The MGLNetworkConfiguration object provides a global way to set a base API URL for + retrieval of map data, styles, and other resources. + + Currently, MGLNetworkConfiguration is private API in code but is able to be used + by any applications via the `MGLMapboxAPIBaseURL` dictionary key in the + application's `Info.plist`. + */ @interface MGLNetworkConfiguration : NSObject /// Returns the shared instance of the `MGLNetworkConfiguration` class. + (instancetype)sharedManager; -/// The current API base URL. -@property (atomic) NSURL *apiBaseURL; +/// The current API base URL. If `nil`, the Mapbox default base API URL is in use. +@property (atomic, nullable) NSURL *apiBaseURL; @end + +NS_ASSUME_NONNULL_END diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 8587f31d3..13ee40c2b 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -65,6 +65,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Fixed a crash that occurred when encountering a rate-limit error in response to a network request. ([#6223](https://github.com/mapbox/mapbox-gl-native/pull/6223)) * Fixed an issue causing an MGLOfflinePack’s progress to continue to update after calling `-suspend`. ([#6186](https://github.com/mapbox/mapbox-gl-native/pull/6186)) * Fixed an issue preventing cached annotation images from displaying while the device is offline. ([#6358](https://github.com/mapbox/mapbox-gl-native/pull/6358)) +* Added support for an `MGLMapboxAPIBaseURL` key in an app's `Info.plist` in order to customize the base URL used for retrieving map data, styles, and other resources. ([#6709](https://github.com/mapbox/mapbox-gl-native/pull/6709)) * Query parameters are no longer stripped from mapbox: URLs used as resource URLs. ([#6182](https://github.com/mapbox/mapbox-gl-native/pull/6182), [#6432](https://github.com/mapbox/mapbox-gl-native/pull/6432)) * Database errors are now logged to the console. ([#6291](https://github.com/mapbox/mapbox-gl-native/pull/6291)) diff --git a/platform/ios/docs/Info.plist Keys.md b/platform/ios/docs/Info.plist Keys.md new file mode 100644 index 000000000..34d3da9e2 --- /dev/null +++ b/platform/ios/docs/Info.plist Keys.md @@ -0,0 +1,21 @@ +# Info.plist Keys + +The Mapbox iOS SDK supports custom `Info.plist` keys in your application in order to configure various settings. + +## MGLMapboxAccessToken + +Set the [Mapbox access token](https://www.mapbox.com/help/define-access-token/) to be used by all instances of `MGLMapView` in the current application. + +Mapbox-hosted vector tiles and styles require an API access token, which you can obtain from the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/). Access tokens associate requests to Mapbox’s vector tile and style APIs with your Mapbox account. They also deter other developers from using your styles without your permission. + +As an alternative, you can use `+[MGLAccountManager setAccessToken:]` to set a token in code. See [our guide](https://www.mapbox.com/help/ios-private-access-token/) for some tips on keeping access tokens in open source code private. + +## MGLMapboxAPIBaseURL + +Use this key if you need to customize the API base URL used throughout the SDK. If unset, the default Mapbox API is used. + +The default value is `https://api.mapbox.com`. + +## MGLMapboxMetricsEnabledSettingShownInApp + +If you have implemented custom opt-out of Mapbox Telemetry within the user interface of your app, use this key to disable the built-in check for opt-out support. See [this guide](https://www.mapbox.com/ios-sdk/#telemetry_opt_out) for more details. diff --git a/platform/ios/scripts/document.sh b/platform/ios/scripts/document.sh index 62ec7824f..4160749e2 100755 --- a/platform/ios/scripts/document.sh +++ b/platform/ios/scripts/document.sh @@ -38,6 +38,7 @@ jazzy \ --github-file-prefix https://github.com/mapbox/mapbox-gl-native/tree/${BRANCH} \ --module-version ${SHORT_VERSION} \ --readme ${README} \ + --documentation="platform/ios/docs/Info.plist Keys.md" \ --root-url https://www.mapbox.com/ios-sdk/api/${RELEASE_VERSION}/ \ --theme platform/darwin/docs/theme \ --output ${OUTPUT} diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index df215f36d..50a1709b0 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -42,6 +42,7 @@ * Fixed an issue preventing cached annotation images from displaying while the device is offline. ([#6358](https://github.com/mapbox/mapbox-gl-native/pull/6358)) * Fixed a crash that could occur when the device is disconnected while downloading an offline pack. ([#6293](https://github.com/mapbox/mapbox-gl-native/pull/6293)) * Fixed a crash that occurred when encountering a rate-limit error in response to a network request. ([#6223](https://github.com/mapbox/mapbox-gl-native/pull/6223)) +* Added support for an `MGLMapboxAPIBaseURL` key in an app's `Info.plist` in order to customize the base URL used for retrieving map data, styles, and other resources. ([#6709](https://github.com/mapbox/mapbox-gl-native/pull/6709)) * Query parameters are no longer stripped from mapbox: URLs used as resource URLs. ([#6182](https://github.com/mapbox/mapbox-gl-native/pull/6182), [#6432](https://github.com/mapbox/mapbox-gl-native/pull/6432)) * Database errors are now logged to the console. ([#6291](https://github.com/mapbox/mapbox-gl-native/pull/6291)) diff --git a/platform/macos/docs/Info.plist Keys.md b/platform/macos/docs/Info.plist Keys.md new file mode 100644 index 000000000..a92b6fe29 --- /dev/null +++ b/platform/macos/docs/Info.plist Keys.md @@ -0,0 +1,17 @@ +# Info.plist Keys + +The Mapbox macOS SDK supports custom `Info.plist` keys in your application in order to configure various settings. + +## MGLMapboxAccessToken + +Set the [Mapbox access token](https://www.mapbox.com/help/define-access-token/) to be used by all instances of `MGLMapView` in the current application. + +Mapbox-hosted vector tiles and styles require an API access token, which you can obtain from the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/). Access tokens associate requests to Mapbox’s vector tile and style APIs with your Mapbox account. They also deter other developers from using your styles without your permission. + +As an alternative, you can use `+[MGLAccountManager setAccessToken:]` to set a token in code. See [our guide](https://www.mapbox.com/help/ios-private-access-token/) for some tips on keeping access tokens in open source code private. + +## MGLMapboxAPIBaseURL + +Use this key if you need to customize the API base URL used throughout the SDK. If unset, the default Mapbox API is used. + +The default value is `https://api.mapbox.com`. diff --git a/platform/macos/scripts/document.sh b/platform/macos/scripts/document.sh index 09656ab01..fc026d08f 100755 --- a/platform/macos/scripts/document.sh +++ b/platform/macos/scripts/document.sh @@ -38,6 +38,7 @@ jazzy \ --github-file-prefix https://github.com/mapbox/mapbox-gl-native/tree/${BRANCH} \ --module-version ${SHORT_VERSION} \ --readme ${README} \ + --documentation="platform/macos/docs/Info.plist Keys.md" \ --theme platform/darwin/docs/theme \ --output ${OUTPUT} # https://github.com/realm/jazzy/issues/411 From 2901bc0f6825f426cbcfd2a9ed78648dc81ab665 Mon Sep 17 00:00:00 2001 From: Jesse Bounds Date: Tue, 1 Nov 2016 11:48:09 -0700 Subject: [PATCH 14/25] Optimize annotation view updates (#5987) Use queryPointAnnotations to drive annotation view updates - Get sets of visible and offscreen annotations using the mbgl query mechanism and updates and enqueues as required - Query viewport adjusted if tilted (avoid apparent issue with queryPointAnnotations when the query box is larger than the actual viewport) - Add a small debugging display in iOS app to see annotations going in and out of the reuse queue This also works around a performance issue that made getting an annotation context expensive by implementing a map of annotations to tags. It works around another issue with the underlying mbgl query so that even if it (rarely) returns an incorrect result, the correct visual effect still occurs and the reuse queue is added to and drained as expected. Finally, this refactors MGLMapView viewForAnnotation: to use the maps to access the requested annotation context and view. This avoids a more expensive lookup done previously. Along for the ride: sync up the ios and macos names (and types) for MGLAnnotationTagContextMap --- platform/ios/CHANGELOG.md | 1 + platform/ios/app/MBXViewController.m | 38 ++++++++- platform/ios/app/Main.storyboard | 62 +++++++++------ platform/ios/src/MGLMapView.mm | 113 ++++++++++++++++++++------- platform/macos/src/MGLMapView.mm | 4 +- 5 files changed, 162 insertions(+), 56 deletions(-) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 13ee40c2b..420714b88 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -46,6 +46,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT ### Annotations * MGLPolyline annotations and the exterior coordinates of MGLPolygon annotations are now able to be mutated, part or all, and changes are displayed immediately. ([#6565](https://github.com/mapbox/mapbox-gl-native/pull/6565)) +* Fixed an issue causing offscreen annotation views to be updated even when they were in the reuse queue. ([#5987](https://github.com/mapbox/mapbox-gl-native/pull/5987)) * Fixed an issue preventing MGLAnnotationView from animating when its coordinate changes. ([#6215](https://github.com/mapbox/mapbox-gl-native/pull/6215)) * Fixed an issue causing the wrong annotation view to be selected when tapping an annotation view with a center offset applied. ([#5931](https://github.com/mapbox/mapbox-gl-native/pull/5931)) * Fixed an issue that assigned annotation views to polyline and polygon annotations. ([#5770](https://github.com/mapbox/mapbox-gl-native/pull/5770)) diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index e8a78abff..6eae0ef77 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -74,7 +74,8 @@ typedef NS_ENUM(NSInteger, MBXSettingsRuntimeStylingRows) { }; typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { - MBXSettingsMiscellaneousWorldTour = 0, + MBXSettingsMiscellaneousShowReuseQueueStats = 0, + MBXSettingsMiscellaneousWorldTour, MBXSettingsMiscellaneousCustomUserDot, MBXSettingsMiscellaneousPrintLogFile, MBXSettingsMiscellaneousDeleteLogFile, @@ -102,11 +103,21 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { UITableViewDataSource, MGLMapViewDelegate> + @property (nonatomic) IBOutlet MGLMapView *mapView; +@property (weak, nonatomic) IBOutlet UILabel *hudLabel; @property (nonatomic) NSInteger styleIndex; @property (nonatomic) BOOL debugLoggingEnabled; @property (nonatomic) BOOL customUserLocationAnnnotationEnabled; @property (nonatomic) BOOL usingLocaleBasedCountryLabels; +@property (nonatomic) BOOL reuseQueueStatsEnabled; + +@end + +@interface MGLMapView (MBXViewController) + +@property (nonatomic) BOOL usingLocaleBasedCountryLabels; +@property (nonatomic) NSDictionary *annotationViewReuseQueueByIdentifier; @end @@ -140,6 +151,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { [self restoreState:nil]; self.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsDebugLoggingEnabled"]; + self.hudLabel.hidden = YES; if ([MGLAccountManager accessToken].length) { @@ -323,6 +335,8 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { ]]; break; case MBXSettingsMiscellaneous: + [settingsTitles addObject:@"Show Reuse Queue Stats"]; + [settingsTitles addObjectsFromArray:@[ @"Start World Tour", [NSString stringWithFormat:@"%@ Custom User Dot", (_customUserLocationAnnnotationEnabled ? @"Disable" : @"Enable")], @@ -335,6 +349,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { @"Delete Telemetry Logfile", ]]; }; + break; default: NSAssert(NO, @"All settings sections should be implemented"); @@ -495,6 +510,12 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { case MBXSettingsMiscellaneousDeleteLogFile: [self deleteTelemetryLogFile]; break; + case MBXSettingsMiscellaneousShowReuseQueueStats: + { + self.reuseQueueStatsEnabled = YES; + self.hudLabel.hidden = NO; + break; + } default: NSAssert(NO, @"All miscellaneous setting rows should be implemented"); break; @@ -1506,9 +1527,24 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { - (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style { // Default Mapbox styles use {name_en} as their label language, which means + NSUInteger queuedAnnotations = 0; // that a device with an English-language locale is already effectively + { // using locale-based country labels. + } _usingLocaleBasedCountryLabels = [[self bestLanguageForUser] isEqualToString:@"en"]; } +- (void)mapViewRegionIsChanging:(MGLMapView *)mapView +{ + if (self.reuseQueueStatsEnabled) { + NSUInteger queuedAnnotations = 0; + for (NSArray *queue in self.mapView.annotationViewReuseQueueByIdentifier.allValues) + { + queuedAnnotations += queue.count; + } + self.hudLabel.text = [NSString stringWithFormat:@"Visible: %ld Queued: %ld", (long)mapView.visibleAnnotations.count, (long)queuedAnnotations]; + } +} + @end diff --git a/platform/ios/app/Main.storyboard b/platform/ios/app/Main.storyboard index 7d8b2c304..5819f17ed 100644 --- a/platform/ios/app/Main.storyboard +++ b/platform/ios/app/Main.storyboard @@ -1,9 +1,11 @@ - - + + - + + + @@ -15,24 +17,35 @@ - + - - + + - + + + @@ -47,7 +60,7 @@