summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvo van Dongen <info@ivovandongen.nl>2018-03-27 00:39:59 +0300
committerIvo van Dongen <ivovandongen@users.noreply.github.com>2018-08-20 22:49:01 +0300
commitca0f2f925d38c190957241f7fa2375a90fa87f45 (patch)
tree92b642bb87e1fd25e22bc9458ae6c7155237472f
parent4fedcf8d061d835e71df80dbc20a32ee4ec8fd21 (diff)
downloadqtlocation-mapboxgl-ca0f2f925d38c190957241f7fa2375a90fa87f45.tar.gz
[darwin] arbitrary offline region geometries
-rw-r--r--platform/darwin/src/MGLOfflinePack.mm21
-rw-r--r--platform/darwin/src/MGLOfflineRegion.h15
-rw-r--r--platform/darwin/src/MGLOfflineRegion_Private.h9
-rw-r--r--platform/darwin/src/MGLOfflineStorage.mm2
-rw-r--r--platform/darwin/src/MGLShapeOfflineRegion.h72
-rw-r--r--platform/darwin/src/MGLShapeOfflineRegion.mm120
-rw-r--r--platform/darwin/src/MGLShapeOfflineRegion_Private.h22
-rw-r--r--platform/darwin/src/MGLTilePyramidOfflineRegion.h14
-rw-r--r--platform/darwin/src/MGLTilePyramidOfflineRegion.mm5
-rw-r--r--platform/darwin/src/MGLTilePyramidOfflineRegion_Private.h22
-rw-r--r--platform/darwin/test/MGLOfflineRegionTests.m18
-rw-r--r--platform/darwin/test/MGLOfflineStorageTests.mm74
-rw-r--r--platform/ios/CHANGELOG.md1
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj24
-rw-r--r--platform/ios/src/Mapbox.h1
-rw-r--r--platform/macos/CHANGELOG.md1
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj16
-rw-r--r--platform/macos/src/Mapbox.h1
18 files changed, 409 insertions, 29 deletions
diff --git a/platform/darwin/src/MGLOfflinePack.mm b/platform/darwin/src/MGLOfflinePack.mm
index 7bbc681c88..bafb976585 100644
--- a/platform/darwin/src/MGLOfflinePack.mm
+++ b/platform/darwin/src/MGLOfflinePack.mm
@@ -3,6 +3,9 @@
#import "MGLOfflineStorage_Private.h"
#import "MGLOfflineRegion_Private.h"
#import "MGLTilePyramidOfflineRegion.h"
+#import "MGLTilePyramidOfflineRegion_Private.h"
+#import "MGLShapeOfflineRegion.h"
+#import "MGLShapeOfflineRegion_Private.h"
#import "NSValue+MGLAdditions.h"
@@ -27,6 +30,12 @@ const MGLExceptionName MGLInvalidOfflinePackException = @"MGLInvalidOfflinePackE
} \
} while (NO);
+@interface MGLTilePyramidOfflineRegion () <MGLOfflineRegion_Private, MGLTilePyramidOfflineRegion_Private>
+@end
+
+@interface MGLShapeOfflineRegion () <MGLOfflineRegion_Private, MGLShapeOfflineRegion_Private>
+@end
+
class MBGLOfflineRegionObserver : public mbgl::OfflineRegionObserver {
public:
MBGLOfflineRegionObserver(MGLOfflinePack *pack_) : pack(pack_) {}
@@ -78,7 +87,17 @@ private:
const mbgl::OfflineRegionDefinition &regionDefinition = _mbglOfflineRegion->getDefinition();
NSAssert([MGLTilePyramidOfflineRegion conformsToProtocol:@protocol(MGLOfflineRegion_Private)], @"MGLTilePyramidOfflineRegion should conform to MGLOfflineRegion_Private.");
- return [(id <MGLOfflineRegion_Private>)[MGLTilePyramidOfflineRegion alloc] initWithOfflineRegionDefinition:regionDefinition];
+ NSAssert([MGLShapeOfflineRegion conformsToProtocol:@protocol(MGLOfflineRegion_Private)], @"MGLShapeOfflineRegion should conform to MGLOfflineRegion_Private.");
+
+
+
+ return regionDefinition.match(
+ [&] (const mbgl::OfflineTilePyramidRegionDefinition def){
+ return (id <MGLOfflineRegion>)[[MGLTilePyramidOfflineRegion alloc] initWithOfflineRegionDefinition:def];
+ },
+ [&] (const mbgl::OfflineGeometryRegionDefinition& def){
+ return (id <MGLOfflineRegion>)[[MGLShapeOfflineRegion alloc] initWithOfflineRegionDefinition:def];
+ });
}
- (NSData *)context {
diff --git a/platform/darwin/src/MGLOfflineRegion.h b/platform/darwin/src/MGLOfflineRegion.h
index fe0ab6cb7f..3e0f485e2c 100644
--- a/platform/darwin/src/MGLOfflineRegion.h
+++ b/platform/darwin/src/MGLOfflineRegion.h
@@ -4,12 +4,21 @@ NS_ASSUME_NONNULL_BEGIN
/**
An object conforming to the `MGLOfflineRegion` protocol determines which
- resources are required by an `MGLOfflinePack` object. At present, only
- instances of `MGLTilePyramidOfflineRegion` may be used as `MGLOfflinePack`
- regions, but additional conforming implementations may be added in the future.
+ resources are required by an `MGLOfflinePack` object.
*/
@protocol MGLOfflineRegion <NSObject>
+/**
+ URL of the style whose resources are required for offline viewing.
+
+ In addition to the JSON stylesheet, different styles may require different font
+ glyphs, sprite sheets, and other resources.
+
+ The URL may be a full HTTP or HTTPS URL or a Mapbox URL indicating the style’s
+ map ID (`mapbox://styles/{user}/{style}`).
+ */
+@property (nonatomic, readonly) NSURL *styleURL;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLOfflineRegion_Private.h b/platform/darwin/src/MGLOfflineRegion_Private.h
index b1dec8dd64..c1f3fd5200 100644
--- a/platform/darwin/src/MGLOfflineRegion_Private.h
+++ b/platform/darwin/src/MGLOfflineRegion_Private.h
@@ -9,15 +9,6 @@ NS_ASSUME_NONNULL_BEGIN
@protocol MGLOfflineRegion_Private <MGLOfflineRegion>
/**
- Initializes and returns an offline region backed by the given C++ region
- definition object.
-
- @param definition A reference to an offline region definition backing the
- offline region.
- */
-- (instancetype)initWithOfflineRegionDefinition:(const mbgl::OfflineRegionDefinition &)definition;
-
-/**
Creates and returns a C++ offline region definition corresponding to the
receiver.
*/
diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm
index 05e1b06338..93a6da36c4 100644
--- a/platform/darwin/src/MGLOfflineStorage.mm
+++ b/platform/darwin/src/MGLOfflineStorage.mm
@@ -285,7 +285,7 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
return;
}
- const mbgl::OfflineTilePyramidRegionDefinition regionDefinition = [(id <MGLOfflineRegion_Private>)region offlineRegionDefinition];
+ const mbgl::OfflineRegionDefinition regionDefinition = [(id <MGLOfflineRegion_Private>)region offlineRegionDefinition];
mbgl::OfflineRegionMetadata metadata(context.length);
[context getBytes:&metadata[0] length:metadata.size()];
self.mbglFileSource->createOfflineRegion(regionDefinition, metadata, [&, completion](mbgl::expected<mbgl::OfflineRegion, std::exception_ptr> mbglOfflineRegion) {
diff --git a/platform/darwin/src/MGLShapeOfflineRegion.h b/platform/darwin/src/MGLShapeOfflineRegion.h
new file mode 100644
index 0000000000..ac54dc137b
--- /dev/null
+++ b/platform/darwin/src/MGLShapeOfflineRegion.h
@@ -0,0 +1,72 @@
+#import <Foundation/Foundation.h>
+
+#import "MGLFoundation.h"
+#import "MGLOfflineRegion.h"
+#import "MGLShape.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ An offline region defined by a style URL, geographic shape, and
+ range of zoom levels.
+
+ This class requires fewer resources than MGLTilePyramidOfflineRegion
+ for irregularly shaped regions.
+ */
+MGL_EXPORT
+@interface MGLShapeOfflineRegion : NSObject <MGLOfflineRegion, NSSecureCoding, NSCopying>
+
+/**
+ The shape for the geographic region covered by the downloaded
+ tiles.
+ */
+@property (nonatomic, readonly) MGLShape *shape;
+
+/**
+ The minimum zoom level for which to download tiles and other resources.
+
+ For more information about zoom levels, `-[MGLMapView zoomLevel]`.
+ */
+@property (nonatomic, readonly) double minimumZoomLevel;
+
+/**
+ The maximum zoom level for which to download tiles and other resources.
+
+ For more information about zoom levels, `-[MGLMapView zoomLevel]`.
+ */
+@property (nonatomic, readonly) double maximumZoomLevel;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/**
+ Initializes a newly created offline region with the given style URL, geometry,
+ and range of zoom levels.
+
+ This is the designated initializer for `MGLShapeOfflineRegion`.
+
+ @param styleURL URL of the map style for which to download resources. The URL
+ may be a full HTTP or HTTPS URL or a Mapbox URL indicating the style’s map
+ ID (`mapbox://styles/{user}/{style}`). Specify `nil` for the default style.
+ Relative file URLs cannot be used as offline style URLs. To download the
+ online resources required by a local style, specify a URL to an online copy
+ of the style.
+ @param shape The shape of the geographic region to be covered by
+ the downloaded tiles.
+ @param minimumZoomLevel The minimum zoom level to be covered by the downloaded
+ tiles. This parameter should be set to at least 0 but no greater than the
+ value of the `maximumZoomLevel` parameter. For each required tile source, if
+ this parameter is set to a value less than the tile source’s minimum zoom
+ level, the download covers zoom levels down to the tile source’s minimum
+ zoom level.
+ @param maximumZoomLevel The maximum zoom level to be covered by the downloaded
+ tiles. This parameter should be set to at least the value of the
+ `minimumZoomLevel` parameter. For each required tile source, if this
+ parameter is set to a value greater than the tile source’s minimum zoom
+ level, the download covers zoom levels up to the tile source’s maximum zoom
+ level.
+ */
+- (instancetype)initWithStyleURL:(nullable NSURL *)styleURL shape:(MGLShape *)shape fromZoomLevel:(double)minimumZoomLevel toZoomLevel:(double)maximumZoomLevel NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLShapeOfflineRegion.mm b/platform/darwin/src/MGLShapeOfflineRegion.mm
new file mode 100644
index 0000000000..e1393f1199
--- /dev/null
+++ b/platform/darwin/src/MGLShapeOfflineRegion.mm
@@ -0,0 +1,120 @@
+#import "MGLShapeOfflineRegion.h"
+
+#if !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+ #import <Cocoa/Cocoa.h>
+#else
+ #import <UIKit/UIKit.h>
+#endif
+
+#import "MGLOfflineRegion_Private.h"
+#import "MGLShapeOfflineRegion_Private.h"
+#import "MGLFeature_Private.h"
+#import "MGLShape_Private.h"
+#import "MGLStyle.h"
+
+@interface MGLShapeOfflineRegion () <MGLOfflineRegion_Private, MGLShapeOfflineRegion_Private>
+
+@end
+
+@implementation MGLShapeOfflineRegion {
+ NSURL *_styleURL;
+}
+
+@synthesize styleURL = _styleURL;
+
++ (BOOL)supportsSecureCoding {
+ return YES;
+}
+
+- (instancetype)init {
+ [NSException raise:@"Method unavailable"
+ format:
+ @"-[MGLShapeOfflineRegion init] is unavailable. "
+ @"Use -initWithStyleURL:shape:fromZoomLevel:toZoomLevel: instead."];
+ return nil;
+}
+
+- (instancetype)initWithStyleURL:(NSURL *)styleURL shape:(MGLShape *)shape fromZoomLevel:(double)minimumZoomLevel toZoomLevel:(double)maximumZoomLevel {
+ if (self = [super init]) {
+ if (!styleURL) {
+ styleURL = [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion];
+ }
+
+ if (!styleURL.scheme) {
+ [NSException raise:@"Invalid style URL" format:
+ @"%@ does not support setting a relative file URL as the style URL. "
+ @"To download the online resources required by this style, "
+ @"specify a URL to an online copy of this style. "
+ @"For Mapbox-hosted styles, use the mapbox: scheme.",
+ NSStringFromClass([self class])];
+ }
+
+ _styleURL = styleURL;
+ _shape = shape;
+ _minimumZoomLevel = minimumZoomLevel;
+ _maximumZoomLevel = maximumZoomLevel;
+ }
+ return self;
+}
+
+- (instancetype)initWithOfflineRegionDefinition:(const mbgl::OfflineGeometryRegionDefinition &)definition {
+ NSURL *styleURL = [NSURL URLWithString:@(definition.styleURL.c_str())];
+ MGLShape *shape = MGLShapeFromGeoJSON(definition.geometry);
+ return [self initWithStyleURL:styleURL shape:shape fromZoomLevel:definition.minZoom toZoomLevel:definition.maxZoom];
+}
+
+- (const mbgl::OfflineRegionDefinition)offlineRegionDefinition {
+#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
+ const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale];
+#elif TARGET_OS_MAC
+ const float scaleFactor = [NSScreen mainScreen].backingScaleFactor;
+#endif
+ return mbgl::OfflineGeometryRegionDefinition(_styleURL.absoluteString.UTF8String,
+ _shape.geometryObject,
+ _minimumZoomLevel, _maximumZoomLevel,
+ scaleFactor);
+}
+
+- (nullable instancetype)initWithCoder:(NSCoder *)coder {
+ NSURL *styleURL = [coder decodeObjectForKey:@"styleURL"];
+ MGLShape * shape = [coder decodeObjectForKey:@"shape"];
+ double minimumZoomLevel = [coder decodeDoubleForKey:@"minimumZoomLevel"];
+ double maximumZoomLevel = [coder decodeDoubleForKey:@"maximumZoomLevel"];
+
+ return [self initWithStyleURL:styleURL shape:shape fromZoomLevel:minimumZoomLevel toZoomLevel:maximumZoomLevel];
+}
+
+- (void)encodeWithCoder:(NSCoder *)coder
+{
+ [coder encodeObject:_styleURL forKey:@"styleURL"];
+ [coder encodeObject:_shape forKey:@"shape"];
+ [coder encodeDouble:_maximumZoomLevel forKey:@"maximumZoomLevel"];
+ [coder encodeDouble:_minimumZoomLevel forKey:@"minimumZoomLevel"];
+}
+
+- (id)copyWithZone:(nullable NSZone *)zone {
+ return [[[self class] allocWithZone:zone] initWithStyleURL:_styleURL shape:_shape fromZoomLevel:_minimumZoomLevel toZoomLevel:_maximumZoomLevel];
+}
+
+- (BOOL)isEqual:(id)other {
+ if (other == self) {
+ return YES;
+ }
+ if (![other isKindOfClass:[self class]]) {
+ return NO;
+ }
+
+ MGLShapeOfflineRegion *otherRegion = other;
+ return (_minimumZoomLevel == otherRegion->_minimumZoomLevel
+ && _maximumZoomLevel == otherRegion->_maximumZoomLevel
+ && _shape.geometryObject == otherRegion->_shape.geometryObject
+ && [_styleURL isEqual:otherRegion->_styleURL]);
+}
+
+- (NSUInteger)hash {
+ return (_styleURL.hash
+ + _shape.hash
+ + @(_minimumZoomLevel).hash + @(_maximumZoomLevel).hash);
+}
+
+@end
diff --git a/platform/darwin/src/MGLShapeOfflineRegion_Private.h b/platform/darwin/src/MGLShapeOfflineRegion_Private.h
new file mode 100644
index 0000000000..2ab44ad405
--- /dev/null
+++ b/platform/darwin/src/MGLShapeOfflineRegion_Private.h
@@ -0,0 +1,22 @@
+#import <Foundation/Foundation.h>
+
+#import "MGLOfflineRegion.h"
+
+#include <mbgl/storage/offline.hpp>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol MGLShapeOfflineRegion_Private <MGLOfflineRegion>
+
+/**
+ Initializes and returns an offline region backed by the given C++ region
+ definition object.
+
+ @param definition A reference to an offline region definition backing the
+ offline region.
+ */
+- (instancetype)initWithOfflineRegionDefinition:(const mbgl::OfflineGeometryRegionDefinition &)definition;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLTilePyramidOfflineRegion.h b/platform/darwin/src/MGLTilePyramidOfflineRegion.h
index 31e5a41920..4fbb68dbc6 100644
--- a/platform/darwin/src/MGLTilePyramidOfflineRegion.h
+++ b/platform/darwin/src/MGLTilePyramidOfflineRegion.h
@@ -9,22 +9,14 @@ NS_ASSUME_NONNULL_BEGIN
/**
An offline region defined by a style URL, geographic coordinate bounds, and
range of zoom levels.
+
+ To minimize the resources required by an irregularly shaped offline region,
+ use the MGLShapeOfflineRegion class instead.
*/
MGL_EXPORT
@interface MGLTilePyramidOfflineRegion : NSObject <MGLOfflineRegion, NSSecureCoding, NSCopying>
/**
- URL of the style whose resources are required for offline viewing.
-
- In addition to the JSON stylesheet, different styles may require different font
- glyphs, sprite sheets, and other resources.
-
- The URL may be a full HTTP or HTTPS URL or a Mapbox URL indicating the style’s
- map ID (`mapbox://styles/{user}/{style}`).
- */
-@property (nonatomic, readonly) NSURL *styleURL;
-
-/**
The coordinate bounds for the geographic region covered by the downloaded
tiles.
*/
diff --git a/platform/darwin/src/MGLTilePyramidOfflineRegion.mm b/platform/darwin/src/MGLTilePyramidOfflineRegion.mm
index 7333703267..0766d224da 100644
--- a/platform/darwin/src/MGLTilePyramidOfflineRegion.mm
+++ b/platform/darwin/src/MGLTilePyramidOfflineRegion.mm
@@ -5,10 +5,11 @@
#endif
#import "MGLOfflineRegion_Private.h"
+#import "MGLTilePyramidOfflineRegion_Private.h"
#import "MGLGeometry_Private.h"
#import "MGLStyle.h"
-@interface MGLTilePyramidOfflineRegion () <MGLOfflineRegion_Private>
+@interface MGLTilePyramidOfflineRegion () <MGLOfflineRegion_Private, MGLTilePyramidOfflineRegion_Private>
@end
@@ -52,7 +53,7 @@
return self;
}
-- (instancetype)initWithOfflineRegionDefinition:(const mbgl::OfflineRegionDefinition &)definition {
+- (instancetype)initWithOfflineRegionDefinition:(const mbgl::OfflineTilePyramidRegionDefinition &)definition {
NSURL *styleURL = [NSURL URLWithString:@(definition.styleURL.c_str())];
MGLCoordinateBounds bounds = MGLCoordinateBoundsFromLatLngBounds(definition.bounds);
return [self initWithStyleURL:styleURL bounds:bounds fromZoomLevel:definition.minZoom toZoomLevel:definition.maxZoom];
diff --git a/platform/darwin/src/MGLTilePyramidOfflineRegion_Private.h b/platform/darwin/src/MGLTilePyramidOfflineRegion_Private.h
new file mode 100644
index 0000000000..90d8e05477
--- /dev/null
+++ b/platform/darwin/src/MGLTilePyramidOfflineRegion_Private.h
@@ -0,0 +1,22 @@
+#import <Foundation/Foundation.h>
+
+#import "MGLOfflineRegion.h"
+
+#include <mbgl/storage/offline.hpp>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol MGLTilePyramidOfflineRegion_Private <MGLOfflineRegion>
+
+/**
+ Initializes and returns an offline region backed by the given C++ region
+ definition object.
+
+ @param definition A reference to an offline region definition backing the
+ offline region.
+ */
+- (instancetype)initWithOfflineRegionDefinition:(const mbgl::OfflineTilePyramidRegionDefinition &)definition;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/test/MGLOfflineRegionTests.m b/platform/darwin/test/MGLOfflineRegionTests.m
index da9928741b..eac6da9b54 100644
--- a/platform/darwin/test/MGLOfflineRegionTests.m
+++ b/platform/darwin/test/MGLOfflineRegionTests.m
@@ -17,7 +17,7 @@
XCTAssertThrowsSpecificNamed([[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:localURL bounds:bounds fromZoomLevel:0 toZoomLevel:DBL_MAX], NSException, MGLInvalidStyleURLException, @"No exception raised when initializing region with a local file URL as the style URL.");
}
-- (void)testEquality {
+- (void)testTilePyramidRegionEquality {
MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(kCLLocationCoordinate2DInvalid, kCLLocationCoordinate2DInvalid);
MGLTilePyramidOfflineRegion *original = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:[MGLStyle lightStyleURLWithVersion:MGLStyleDefaultVersion] bounds:bounds fromZoomLevel:5 toZoomLevel:10];
MGLTilePyramidOfflineRegion *copy = [original copy];
@@ -29,4 +29,20 @@
XCTAssertEqual(original.maximumZoomLevel, original.maximumZoomLevel, @"Maximum zoom level has changed.");
}
+- (void)testGeometryRegionEquality {
+ NSString *geojson = @"{\"type\": \"Point\", \"coordinates\": [-3.8671874999999996, 52.482780222078226] }";
+ NSError *error;
+ MGLShape *shape = [MGLShape shapeWithData: [geojson dataUsingEncoding:NSUTF8StringEncoding] encoding: NSUTF8StringEncoding error:&error];
+ XCTAssertNil(error);
+
+ MGLShapeOfflineRegion *original = [[MGLShapeOfflineRegion alloc] initWithStyleURL:[MGLStyle lightStyleURLWithVersion:MGLStyleDefaultVersion] shape:shape fromZoomLevel:5 toZoomLevel:10];
+ MGLShapeOfflineRegion *copy = [original copy];
+ XCTAssertEqualObjects(original, copy, @"Shape region should be equal to its copy.");
+
+ XCTAssertEqualObjects(original.styleURL, copy.styleURL, @"Style URL has changed.");
+ XCTAssertEqualObjects(original.shape, copy.shape, @"Geometry has changed.");
+ XCTAssertEqual(original.minimumZoomLevel, original.minimumZoomLevel, @"Minimum zoom level has changed.");
+ XCTAssertEqual(original.maximumZoomLevel, original.maximumZoomLevel, @"Maximum zoom level has changed.");
+}
+
@end
diff --git a/platform/darwin/test/MGLOfflineStorageTests.mm b/platform/darwin/test/MGLOfflineStorageTests.mm
index 28c6633028..e9e2467f21 100644
--- a/platform/darwin/test/MGLOfflineStorageTests.mm
+++ b/platform/darwin/test/MGLOfflineStorageTests.mm
@@ -36,7 +36,7 @@
XCTAssertEqual([MGLOfflineStorage sharedOfflineStorage], [MGLOfflineStorage sharedOfflineStorage], @"There should only be one shared offline storage object.");
}
-- (void)testAddPack {
+- (void)testAddPackForBounds {
NSUInteger countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count;
NSURL *styleURL = [MGLStyle lightStyleURLWithVersion:8];
@@ -109,6 +109,78 @@
[self waitForExpectationsWithTimeout:1 handler:nil];
}
+- (void)testAddPackForGeometry {
+ NSUInteger countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count;
+
+ NSURL *styleURL = [MGLStyle lightStyleURLWithVersion:8];
+ double zoomLevel = 20;
+ NSString *geojson = @"{ \"type\": \"Polygon\", \"coordinates\": [ [ [ 5.1299285888671875, 52.10365839097971 ], [ 5.103063583374023, 52.110037078604236 ], [ 5.080232620239258, 52.09548601177304 ], [ 5.106925964355469, 52.07987524347506 ], [ 5.1299285888671875, 52.10365839097971 ] ] ]}";
+ NSError *error;
+ MGLShape *shape = [MGLShape shapeWithData: [geojson dataUsingEncoding:NSUTF8StringEncoding] encoding: NSUTF8StringEncoding error:&error];
+ XCTAssertNil(error);
+ MGLShapeOfflineRegion *region = [[MGLShapeOfflineRegion alloc] initWithStyleURL:styleURL shape:shape fromZoomLevel:zoomLevel toZoomLevel:zoomLevel];
+
+
+ NSString *nameKey = @"Name";
+ NSString *name = @"Utrecht centrum";
+
+ NSData *context = [NSKeyedArchiver archivedDataWithRootObject:@{nameKey: name}];
+
+ __block MGLOfflinePack *pack;
+ [self keyValueObservingExpectationForObject:[MGLOfflineStorage sharedOfflineStorage] keyPath:@"packs" handler:^BOOL(id _Nonnull observedObject, NSDictionary * _Nonnull change) {
+ const auto changeKind = static_cast<NSKeyValueChange>([change[NSKeyValueChangeKindKey] unsignedLongValue]);
+ NSIndexSet *indices = change[NSKeyValueChangeIndexesKey];
+ return changeKind == NSKeyValueChangeInsertion && indices.count == 1;
+ }];
+ XCTestExpectation *additionCompletionHandlerExpectation = [self expectationWithDescription:@"add pack completion handler"];
+ [[MGLOfflineStorage sharedOfflineStorage] addPackForRegion:region withContext:context completionHandler:^(MGLOfflinePack * _Nullable completionHandlerPack, NSError * _Nullable error) {
+ XCTAssertNotNil(completionHandlerPack, @"Added pack should exist.");
+ XCTAssertEqual(completionHandlerPack.state, MGLOfflinePackStateInactive, @"New pack should initially have inactive state.");
+ pack = completionHandlerPack;
+ [additionCompletionHandlerExpectation fulfill];
+ }];
+ [self waitForExpectationsWithTimeout:2 handler:nil];
+
+ XCTAssertEqual([MGLOfflineStorage sharedOfflineStorage].packs.count, countOfPacks + 1, @"Added pack should have been added to the canonical collection of packs owned by the shared offline storage object. This assertion can fail if this test is run before -testAAALoadPacks.");
+
+ XCTAssertEqual(pack, [MGLOfflineStorage sharedOfflineStorage].packs.lastObject, @"Pack should be appended to end of packs array.");
+
+ XCTAssertEqualObjects(pack.region, region, @"Added pack’s region has changed.");
+
+ NSDictionary *userInfo = [NSKeyedUnarchiver unarchiveObjectWithData:pack.context];
+ XCTAssert([userInfo isKindOfClass:[NSDictionary class]], @"Context of offline pack isn’t a dictionary.");
+ XCTAssert([userInfo[nameKey] isKindOfClass:[NSString class]], @"Name of offline pack isn’t a string.");
+ XCTAssertEqualObjects(userInfo[nameKey], name, @"Name of offline pack has changed.");
+
+ XCTAssertEqual(pack.state, MGLOfflinePackStateInactive, @"New pack should initially have inactive state.");
+
+ [self keyValueObservingExpectationForObject:pack keyPath:@"state" handler:^BOOL(id _Nonnull observedObject, NSDictionary * _Nonnull change) {
+ const auto changeKind = static_cast<NSKeyValueChange>([change[NSKeyValueChangeKindKey] unsignedLongValue]);
+ const auto state = static_cast<MGLOfflinePackState>([change[NSKeyValueChangeNewKey] longValue]);
+ return changeKind == NSKeyValueChangeSetting && state == MGLOfflinePackStateInactive;
+ }];
+ [self expectationForNotification:MGLOfflinePackProgressChangedNotification object:pack handler:^BOOL(NSNotification * _Nonnull notification) {
+ MGLOfflinePack *notificationPack = notification.object;
+ XCTAssert([notificationPack isKindOfClass:[MGLOfflinePack class]], @"Object of notification should be an MGLOfflinePack.");
+
+ NSDictionary *userInfo = notification.userInfo;
+ XCTAssertNotNil(userInfo, @"Progress change notification should have a userInfo dictionary.");
+
+ NSNumber *stateNumber = userInfo[MGLOfflinePackUserInfoKeyState];
+ XCTAssert([stateNumber isKindOfClass:[NSNumber class]], @"Progress change notification’s state should be an NSNumber.");
+ XCTAssertEqual(stateNumber.integerValue, pack.state, @"State in a progress change notification should match the pack’s state.");
+
+ NSValue *progressValue = userInfo[MGLOfflinePackUserInfoKeyProgress];
+ XCTAssert([progressValue isKindOfClass:[NSValue class]], @"Progress change notification’s progress should be an NSValue.");
+ XCTAssertEqualObjects(progressValue, [NSValue valueWithMGLOfflinePackProgress:pack.progress], @"Progress change notification’s progress should match pack’s progress.");
+
+ return notificationPack == pack && pack.state == MGLOfflinePackStateInactive;
+ }];
+ [pack requestProgress];
+ [self waitForExpectationsWithTimeout:1 handler:nil];
+ pack = nil;
+}
+
- (void)testBackupExclusion {
NSURL *cacheDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory
inDomain:NSUserDomainMask
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index 0bb97eaec3..edebf57dc6 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -8,6 +8,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* When a symbol in an `MGLSymbolStyleLayer` has both an icon and text, both are shown or hidden together based on available space. ([#12521](https://github.com/mapbox/mapbox-gl-native/pull/12521))
* The `-[MGLMapView visibleFeaturesAtPoint:]` method can now return features near tile boundaries at high zoom levels. ([#12570](https://github.com/mapbox/mapbox-gl-native/pull/12570))
* Fixed inconsistencies in exception naming. ([#12583](https://github.com/mapbox/mapbox-gl-native/issues/12583))
+* Added `MGLShapeOfflineRegion` for defining arbitrarily shaped offline regions [#11447](https://github.com/mapbox/mapbox-gl-native/pull/11447)
## 4.3.0 - August 15, 2018
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index 980fa0321c..3875d46865 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -294,6 +294,8 @@
8989B17E201A48EB0081CF59 /* MGLHeatmapStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8989B17B201A48EA0081CF59 /* MGLHeatmapStyleLayer.mm */; };
8989B17F201A48EB0081CF59 /* MGLHeatmapStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8989B17B201A48EA0081CF59 /* MGLHeatmapStyleLayer.mm */; };
920A3E5D1E6F995200C16EFC /* MGLSourceQueryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 920A3E5C1E6F995200C16EFC /* MGLSourceQueryTests.m */; };
+ 9221BAAD2069843A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9221BAAC2069843A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h */; };
+ 9221BAB020699F8A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9221BAAC2069843A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h */; };
927FBCFC1F4DAA8300F8BF1F /* MBXSnapshotsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 927FBCFB1F4DAA8300F8BF1F /* MBXSnapshotsViewController.m */; };
927FBCFF1F4DB05500F8BF1F /* MGLMapSnapshotter.h in Headers */ = {isa = PBXBuildFile; fileRef = 927FBCFD1F4DB05500F8BF1F /* MGLMapSnapshotter.h */; settings = {ATTRIBUTES = (Public, ); }; };
927FBD001F4DB05500F8BF1F /* MGLMapSnapshotter.h in Headers */ = {isa = PBXBuildFile; fileRef = 927FBCFD1F4DB05500F8BF1F /* MGLMapSnapshotter.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -301,6 +303,12 @@
927FBD021F4DB05500F8BF1F /* MGLMapSnapshotter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 927FBCFE1F4DB05500F8BF1F /* MGLMapSnapshotter.mm */; };
929EFFAB1F56DCD4003A77D5 /* MGLAnnotationView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4018B1C41CDC277F00F666AF /* MGLAnnotationView.mm */; };
92F2C3ED1F0E3C3A00268EC0 /* MGLRendererFrontend.h in Headers */ = {isa = PBXBuildFile; fileRef = 92F2C3EC1F0E3C3A00268EC0 /* MGLRendererFrontend.h */; };
+ 92FC0AEA207CEE16007B6B54 /* MGLShapeOfflineRegion.h in Headers */ = {isa = PBXBuildFile; fileRef = 92FC0AE7207CEE16007B6B54 /* MGLShapeOfflineRegion.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 92FC0AEB207CEE16007B6B54 /* MGLShapeOfflineRegion.h in Headers */ = {isa = PBXBuildFile; fileRef = 92FC0AE7207CEE16007B6B54 /* MGLShapeOfflineRegion.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 92FC0AEC207CEE16007B6B54 /* MGLShapeOfflineRegion_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 92FC0AE8207CEE16007B6B54 /* MGLShapeOfflineRegion_Private.h */; };
+ 92FC0AED207CEE16007B6B54 /* MGLShapeOfflineRegion_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 92FC0AE8207CEE16007B6B54 /* MGLShapeOfflineRegion_Private.h */; };
+ 92FC0AEE207CEE16007B6B54 /* MGLShapeOfflineRegion.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92FC0AE9207CEE16007B6B54 /* MGLShapeOfflineRegion.mm */; };
+ 92FC0AEF207CEE16007B6B54 /* MGLShapeOfflineRegion.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92FC0AE9207CEE16007B6B54 /* MGLShapeOfflineRegion.mm */; };
96036A01200565C700510F3D /* NSOrthography+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 960369FF200565C700510F3D /* NSOrthography+MGLAdditions.h */; };
96036A02200565C700510F3D /* NSOrthography+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 960369FF200565C700510F3D /* NSOrthography+MGLAdditions.h */; };
96036A03200565C700510F3D /* NSOrthography+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 96036A00200565C700510F3D /* NSOrthography+MGLAdditions.m */; };
@@ -973,11 +981,15 @@
8989B17A201A48EA0081CF59 /* MGLHeatmapStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLHeatmapStyleLayer.h; sourceTree = "<group>"; };
8989B17B201A48EA0081CF59 /* MGLHeatmapStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLHeatmapStyleLayer.mm; sourceTree = "<group>"; };
920A3E5C1E6F995200C16EFC /* MGLSourceQueryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLSourceQueryTests.m; path = ../../darwin/test/MGLSourceQueryTests.m; sourceTree = "<group>"; };
+ 9221BAAC2069843A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTilePyramidOfflineRegion_Private.h; sourceTree = "<group>"; };
927FBCFA1F4DAA8300F8BF1F /* MBXSnapshotsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBXSnapshotsViewController.h; sourceTree = "<group>"; };
927FBCFB1F4DAA8300F8BF1F /* MBXSnapshotsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBXSnapshotsViewController.m; sourceTree = "<group>"; };
927FBCFD1F4DB05500F8BF1F /* MGLMapSnapshotter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapSnapshotter.h; sourceTree = "<group>"; };
927FBCFE1F4DB05500F8BF1F /* MGLMapSnapshotter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLMapSnapshotter.mm; sourceTree = "<group>"; };
92F2C3EC1F0E3C3A00268EC0 /* MGLRendererFrontend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLRendererFrontend.h; sourceTree = "<group>"; };
+ 92FC0AE7207CEE16007B6B54 /* MGLShapeOfflineRegion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeOfflineRegion.h; sourceTree = "<group>"; };
+ 92FC0AE8207CEE16007B6B54 /* MGLShapeOfflineRegion_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeOfflineRegion_Private.h; sourceTree = "<group>"; };
+ 92FC0AE9207CEE16007B6B54 /* MGLShapeOfflineRegion.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLShapeOfflineRegion.mm; sourceTree = "<group>"; };
960369FF200565C700510F3D /* NSOrthography+MGLAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSOrthography+MGLAdditions.h"; sourceTree = "<group>"; };
96036A00200565C700510F3D /* NSOrthography+MGLAdditions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSOrthography+MGLAdditions.m"; sourceTree = "<group>"; };
96036A0520059BBA00510F3D /* MGLNSOrthographyAdditionsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLNSOrthographyAdditionsTests.m; sourceTree = "<group>"; };
@@ -2118,7 +2130,11 @@
DA8847E61CBAFA5100AB86E3 /* MGLOfflineStorage.h */,
DA8848091CBAFA6200AB86E3 /* MGLOfflineStorage_Private.h */,
DA88480A1CBAFA6200AB86E3 /* MGLOfflineStorage.mm */,
+ 92FC0AE8207CEE16007B6B54 /* MGLShapeOfflineRegion_Private.h */,
+ 92FC0AE7207CEE16007B6B54 /* MGLShapeOfflineRegion.h */,
+ 92FC0AE9207CEE16007B6B54 /* MGLShapeOfflineRegion.mm */,
DA8847ED1CBAFA5100AB86E3 /* MGLTilePyramidOfflineRegion.h */,
+ 9221BAAC2069843A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h */,
DA8848101CBAFA6200AB86E3 /* MGLTilePyramidOfflineRegion.mm */,
);
name = "Offline Maps";
@@ -2211,6 +2227,7 @@
buildActionMask = 2147483647;
files = (
556660DB1E1D8E8D00E2C41B /* MGLFoundation.h in Headers */,
+ 92FC0AEA207CEE16007B6B54 /* MGLShapeOfflineRegion.h in Headers */,
35D13AC31D3D19DD00AFB4E0 /* MGLFillStyleLayer.h in Headers */,
DA88483A1CBAFB8500AB86E3 /* MGLAnnotationImage.h in Headers */,
DAF2571B201901E200367EF5 /* MGLHillshadeStyleLayer.h in Headers */,
@@ -2277,6 +2294,7 @@
071BBB031EE76146001FB02A /* MGLImageSource.h in Headers */,
DA8847F41CBAFA5100AB86E3 /* MGLOfflinePack.h in Headers */,
DA88482E1CBAFA6200AB86E3 /* NSException+MGLAdditions.h in Headers */,
+ 9221BAAD2069843A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h in Headers */,
96F3F73C1F57124B003E2D2C /* MGLUserLocationHeadingIndicator.h in Headers */,
408AA8571DAEDA1700022900 /* NSDictionary+MGLAdditions.h in Headers */,
DA88483F1CBAFB8500AB86E3 /* MGLUserLocation.h in Headers */,
@@ -2321,6 +2339,7 @@
DA8847F51CBAFA5100AB86E3 /* MGLOfflineRegion.h in Headers */,
DA737EE11D056A4E005BDA16 /* MGLMapViewDelegate.h in Headers */,
ACF969F420CB04E600B23FB7 /* MMEEventsService.h in Headers */,
+ 92FC0AEC207CEE16007B6B54 /* MGLShapeOfflineRegion_Private.h in Headers */,
AC518DFF201BB55A00EBC820 /* MGLTelemetryConfig.h in Headers */,
DA88481B1CBAFA6200AB86E3 /* MGLGeometry_Private.h in Headers */,
3510FFF91D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.h in Headers */,
@@ -2351,6 +2370,7 @@
556660CA1E1BF3A900E2C41B /* MGLFoundation.h in Headers */,
96E516ED200058A200A02306 /* MGLComputedShapeSource.h in Headers */,
35B82BF91D6C5F8400B1B721 /* NSPredicate+MGLAdditions.h in Headers */,
+ 92FC0AEB207CEE16007B6B54 /* MGLShapeOfflineRegion.h in Headers */,
DA35A2CA1CCAAAD200E826B2 /* NSValue+MGLAdditions.h in Headers */,
350098BC1D480108004B2AF0 /* MGLVectorTileSource.h in Headers */,
FA68F14B1E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.h in Headers */,
@@ -2379,6 +2399,7 @@
CA55CD42202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */,
DABFB86D1CBE9A0F00D62B32 /* MGLAnnotationImage.h in Headers */,
DABFB8721CBE9A0F00D62B32 /* MGLUserLocation.h in Headers */,
+ 92FC0AED207CEE16007B6B54 /* MGLShapeOfflineRegion_Private.h in Headers */,
927FBD001F4DB05500F8BF1F /* MGLMapSnapshotter.h in Headers */,
3566C7721D4A9198008152BC /* MGLSource_Private.h in Headers */,
353933FF1D3FB7DD003F57D7 /* MGLSymbolStyleLayer.h in Headers */,
@@ -2455,6 +2476,7 @@
96E516E02000550C00A02306 /* MGLFeature_Private.h in Headers */,
353933F61D3FB785003F57D7 /* MGLBackgroundStyleLayer.h in Headers */,
DABFB85D1CBE99E500D62B32 /* MGLAccountManager.h in Headers */,
+ 9221BAB020699F8A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h in Headers */,
96E516F5200059B100A02306 /* MGLNetworkConfiguration.h in Headers */,
96E516F42000597D00A02306 /* NSData+MGLAdditions.h in Headers */,
96E516DD200054F200A02306 /* MGLPolygon_Private.h in Headers */,
@@ -3010,6 +3032,7 @@
40834C441FE05F7500C1BD0D /* reporting_utils.m in Sources */,
408AA8581DAEDA1E00022900 /* NSDictionary+MGLAdditions.mm in Sources */,
DA35A2A11CC9E95F00E826B2 /* MGLCoordinateFormatter.m in Sources */,
+ 92FC0AEE207CEE16007B6B54 /* MGLShapeOfflineRegion.mm in Sources */,
35305D481D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */,
40834BF61FE05E1800C1BD0D /* MMEUIApplicationWrapper.m in Sources */,
DA8848291CBAFA6200AB86E3 /* MGLStyle.mm in Sources */,
@@ -3137,6 +3160,7 @@
40834C511FE05F7600C1BD0D /* reporting_utils.m in Sources */,
35305D491D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */,
357FE2E01E02D2B20068B753 /* NSCoder+MGLAdditions.mm in Sources */,
+ 92FC0AEF207CEE16007B6B54 /* MGLShapeOfflineRegion.mm in Sources */,
DAA4E42D1CBB730400178DFB /* MGLAnnotationImage.m in Sources */,
40834C0A1FE05E1800C1BD0D /* MMEUIApplicationWrapper.m in Sources */,
558DE7A31E5615E400C7916D /* MGLFoundation.mm in Sources */,
diff --git a/platform/ios/src/Mapbox.h b/platform/ios/src/Mapbox.h
index a0afe2d9cc..2af80b455d 100644
--- a/platform/ios/src/Mapbox.h
+++ b/platform/ios/src/Mapbox.h
@@ -57,6 +57,7 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLRasterTileSource.h"
#import "MGLRasterDEMSource.h"
#import "MGLImageSource.h"
+#import "MGLShapeOfflineRegion.h"
#import "MGLTilePyramidOfflineRegion.h"
#import "MGLTypes.h"
#import "MGLUserLocation.h"
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index 41063670a8..1e6a54d8e9 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -5,6 +5,7 @@
* When a symbol in an `MGLSymbolStyleLayer` has both an icon and text, both are shown or hidden together based on available space. ([#12521](https://github.com/mapbox/mapbox-gl-native/pull/12521))
* The `-[MGLMapView annotationAtPoint:]` method can now return annotations near tile boundaries at high zoom levels. ([#12570](https://github.com/mapbox/mapbox-gl-native/pull/12570))
* Fixed inconsistencies in exception naming. ([#12583](https://github.com/mapbox/mapbox-gl-native/issues/12583))
+* Added `MGLShapeOfflineRegion` for defining arbitrarily shaped offline regions [#11447](https://github.com/mapbox/mapbox-gl-native/pull/11447)
# 0.10.0 - August 15, 2018
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 3ee1b8eab4..1785caddb9 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -93,7 +93,11 @@
92092EF01F5EB10E00AF5130 /* MGLMapSnapshotter.h in Headers */ = {isa = PBXBuildFile; fileRef = 92092EEE1F5EB10E00AF5130 /* MGLMapSnapshotter.h */; settings = {ATTRIBUTES = (Public, ); }; };
92092EF11F5EB10E00AF5130 /* MGLMapSnapshotter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92092EEF1F5EB10E00AF5130 /* MGLMapSnapshotter.mm */; };
920A3E591E6F859D00C16EFC /* MGLSourceQueryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 920A3E581E6F859D00C16EFC /* MGLSourceQueryTests.m */; };
+ 9221BAAF20699CBB0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9221BAAE20699CBA0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h */; };
+ 9250B8C32073C69100EF338C /* MGLShapeOfflineRegion.h in Headers */ = {isa = PBXBuildFile; fileRef = 9250B8C22073C69000EF338C /* MGLShapeOfflineRegion.h */; settings = {ATTRIBUTES = (Public, ); }; };
92F2C3EB1F0E3A1900268EC0 /* MGLRendererFrontend.h in Headers */ = {isa = PBXBuildFile; fileRef = 92F2C3EA1F0E3A1900268EC0 /* MGLRendererFrontend.h */; };
+ 92FC0AE4207CC8DA007B6B54 /* MGLShapeOfflineRegion_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 92FC0AE3207CC8DA007B6B54 /* MGLShapeOfflineRegion_Private.h */; };
+ 92FC0AE6207CDD8D007B6B54 /* MGLShapeOfflineRegion.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92FC0AE5207CDD8D007B6B54 /* MGLShapeOfflineRegion.mm */; };
9654C12B1FFC38E000DB6A19 /* MGLPolyline_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9654C12A1FFC38E000DB6A19 /* MGLPolyline_Private.h */; };
9654C12D1FFC394700DB6A19 /* MGLPolygon_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9654C12C1FFC394700DB6A19 /* MGLPolygon_Private.h */; };
96E027311E57C9A7004B8E66 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 96E027331E57C9A7004B8E66 /* Localizable.strings */; };
@@ -383,7 +387,11 @@
92092EEE1F5EB10E00AF5130 /* MGLMapSnapshotter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapSnapshotter.h; sourceTree = "<group>"; };
92092EEF1F5EB10E00AF5130 /* MGLMapSnapshotter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLMapSnapshotter.mm; sourceTree = "<group>"; };
920A3E581E6F859D00C16EFC /* MGLSourceQueryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLSourceQueryTests.m; sourceTree = "<group>"; };
+ 9221BAAE20699CBA0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTilePyramidOfflineRegion_Private.h; sourceTree = "<group>"; };
+ 9250B8C22073C69000EF338C /* MGLShapeOfflineRegion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeOfflineRegion.h; sourceTree = "<group>"; };
92F2C3EA1F0E3A1900268EC0 /* MGLRendererFrontend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLRendererFrontend.h; sourceTree = "<group>"; };
+ 92FC0AE3207CC8DA007B6B54 /* MGLShapeOfflineRegion_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeOfflineRegion_Private.h; sourceTree = "<group>"; };
+ 92FC0AE5207CDD8D007B6B54 /* MGLShapeOfflineRegion.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLShapeOfflineRegion.mm; sourceTree = "<group>"; };
9654C12A1FFC38E000DB6A19 /* MGLPolyline_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPolyline_Private.h; sourceTree = "<group>"; };
9654C12C1FFC394700DB6A19 /* MGLPolygon_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPolygon_Private.h; sourceTree = "<group>"; };
966091701E5BBFF700A9A03B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -1007,7 +1015,11 @@
DAE6C3511CC31E0400DB3429 /* MGLOfflineStorage.h */,
DAE6C3741CC31E2A00DB3429 /* MGLOfflineStorage_Private.h */,
DAE6C3751CC31E2A00DB3429 /* MGLOfflineStorage.mm */,
+ 9250B8C22073C69000EF338C /* MGLShapeOfflineRegion.h */,
+ 92FC0AE3207CC8DA007B6B54 /* MGLShapeOfflineRegion_Private.h */,
+ 92FC0AE5207CDD8D007B6B54 /* MGLShapeOfflineRegion.mm */,
DAE6C3581CC31E0400DB3429 /* MGLTilePyramidOfflineRegion.h */,
+ 9221BAAE20699CBA0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h */,
DAE6C37B1CC31E2A00DB3429 /* MGLTilePyramidOfflineRegion.mm */,
);
name = "Offline Maps";
@@ -1214,6 +1226,7 @@
352742781D4C220900A1ECE6 /* MGLStyleValue.h in Headers */,
DAE6C35E1CC31E0400DB3429 /* MGLMultiPoint.h in Headers */,
35602BFF1D3EA9B40050646F /* MGLStyleLayer_Private.h in Headers */,
+ 92FC0AE4207CC8DA007B6B54 /* MGLShapeOfflineRegion_Private.h in Headers */,
DAF0D8161DFE6B1800B28378 /* MGLAttributionInfo_Private.h in Headers */,
DAE6C3971CC31E2A00DB3429 /* NSBundle+MGLAdditions.h in Headers */,
DAED385F1D62CED700D7640F /* NSURL+MGLAdditions.h in Headers */,
@@ -1246,6 +1259,7 @@
35602BFA1D3EA99F0050646F /* MGLFillStyleLayer.h in Headers */,
DA35A2A41CC9EB1A00E826B2 /* MGLCoordinateFormatter.h in Headers */,
35C5D8491D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.h in Headers */,
+ 9250B8C32073C69100EF338C /* MGLShapeOfflineRegion.h in Headers */,
DD0902B31DB1AC6400C5BDCE /* MGLNetworkConfiguration.h in Headers */,
DAE6C3621CC31E0400DB3429 /* MGLOverlay.h in Headers */,
DAE6C3651CC31E0400DB3429 /* MGLPolyline.h in Headers */,
@@ -1287,6 +1301,7 @@
352742851D4C244700A1ECE6 /* MGLRasterTileSource.h in Headers */,
9654C12D1FFC394700DB6A19 /* MGLPolygon_Private.h in Headers */,
408AA85B1DAEECFE00022900 /* MGLShape_Private.h in Headers */,
+ 9221BAAF20699CBB0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h in Headers */,
DACC22181CF3D4F700D220D9 /* MGLFeature_Private.h in Headers */,
9654C12B1FFC38E000DB6A19 /* MGLPolyline_Private.h in Headers */,
DA6408D71DA4E5DA00908C90 /* MGLVectorStyleLayer.h in Headers */,
@@ -1568,6 +1583,7 @@
DAE6C3B51CC31EF300DB3429 /* MGLCompassCell.m in Sources */,
DA8F25901D51CA600010E6B5 /* MGLRasterStyleLayer.mm in Sources */,
DAD165751CF4CD7A001FF4B9 /* MGLShapeCollection.mm in Sources */,
+ 92FC0AE6207CDD8D007B6B54 /* MGLShapeOfflineRegion.mm in Sources */,
35C5D8481D6DD66D00E95907 /* NSComparisonPredicate+MGLAdditions.mm in Sources */,
DA35A2AE1CCA091800E826B2 /* MGLCompassDirectionFormatter.m in Sources */,
DACA8623201920BE00E9693A /* MGLRasterDEMSource.mm in Sources */,
diff --git a/platform/macos/src/Mapbox.h b/platform/macos/src/Mapbox.h
index 198998a874..dcffd73dfc 100644
--- a/platform/macos/src/Mapbox.h
+++ b/platform/macos/src/Mapbox.h
@@ -56,6 +56,7 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLRasterDEMSource.h"
#import "MGLImageSource.h"
#import "MGLTilePyramidOfflineRegion.h"
+#import "MGLShapeOfflineRegion.h"
#import "MGLTypes.h"
#import "NSValue+MGLAdditions.h"
#import "MGLStyleValue.h"