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

Commit

Permalink
[darwin] arbitrary offline region geometries
Browse files Browse the repository at this point in the history
  • Loading branch information
ivovandongen committed Aug 20, 2018
1 parent 1a9326f commit 1a4cc2c
Show file tree
Hide file tree
Showing 18 changed files with 409 additions and 29 deletions.
21 changes: 20 additions & 1 deletion platform/darwin/src/MGLOfflinePack.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -27,6 +30,12 @@
} \
} 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_) {}
Expand Down Expand Up @@ -78,7 +87,17 @@ - (void)dealloc {

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 {
Expand Down
15 changes: 12 additions & 3 deletions platform/darwin/src/MGLOfflineRegion.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 0 additions & 9 deletions platform/darwin/src/MGLOfflineRegion_Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,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.
Expand Down
2 changes: 1 addition & 1 deletion platform/darwin/src/MGLOfflineStorage.mm
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ - (void)_addPackForRegion:(id <MGLOfflineRegion>)region withContext:(NSData *)co
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) {
Expand Down
72 changes: 72 additions & 0 deletions platform/darwin/src/MGLShapeOfflineRegion.h
Original file line number Diff line number Diff line change
@@ -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
120 changes: 120 additions & 0 deletions platform/darwin/src/MGLShapeOfflineRegion.mm
Original file line number Diff line number Diff line change
@@ -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
22 changes: 22 additions & 0 deletions platform/darwin/src/MGLShapeOfflineRegion_Private.h
Original file line number Diff line number Diff line change
@@ -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
14 changes: 3 additions & 11 deletions platform/darwin/src/MGLTilePyramidOfflineRegion.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,13 @@ 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.
Expand Down
5 changes: 3 additions & 2 deletions platform/darwin/src/MGLTilePyramidOfflineRegion.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -52,7 +53,7 @@ - (instancetype)initWithStyleURL:(NSURL *)styleURL bounds:(MGLCoordinateBounds)b
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];
Expand Down
22 changes: 22 additions & 0 deletions platform/darwin/src/MGLTilePyramidOfflineRegion_Private.h
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 1a4cc2c

Please sign in to comment.