From de9098cf99463e433e9e9d6088865bc63948e567 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Mon, 9 Oct 2017 19:50:21 +0300 Subject: [darwin][ios][macos] map snapshotter - add MGLMapSnapshot wrapper --- platform/darwin/src/MGLMapSnapshotter.h | 62 ++++++++++++++-------- platform/darwin/src/MGLMapSnapshotter.mm | 34 ++++++++++-- .../darwin/test/MGLDocumentationExampleTests.swift | 18 +++++++ platform/ios/app/MBXSnapshotsViewController.m | 4 +- platform/macos/app/MapDocument.m | 6 +-- 5 files changed, 94 insertions(+), 30 deletions(-) diff --git a/platform/darwin/src/MGLMapSnapshotter.h b/platform/darwin/src/MGLMapSnapshotter.h index 896dc04c9d..4a59cc3b39 100644 --- a/platform/darwin/src/MGLMapSnapshotter.h +++ b/platform/darwin/src/MGLMapSnapshotter.h @@ -70,23 +70,42 @@ MGL_EXPORT @end +/** + An image generated by a snapshotter object. + */ +@interface MGLMapSnapshot : NSObject + #if TARGET_OS_IPHONE /** - A block to processes the result or error of a snapshot request. - - @param snapshot The `UIImage` that was generated or `nil` if an error occurred. - @param error The error that occured or `nil` when successful. + Converts the specified map coordinate to a point in the coordinate space of the image. */ -typedef void (^MGLMapSnapshotCompletionHandler)(UIImage* _Nullable snapshot, NSError* _Nullable error); +- (CGPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate; + +/** + The image of the map’s content. + */ +@property(nonatomic, readonly) UIImage *image; #else +/** + Converts the specified map coordinate to a point in the coordinate space of the image. + */ +- (NSPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate; + +/** + The image of the map’s content. + */ +@property(nonatomic, readonly) NSImage *image; +#endif + +@end + /** A block to processes the result or error of a snapshot request. - @param snapshot The `NSImage` that was generated or `nil` if an error occurred. - @param error The eror that occured or `nil` when succesful. + @param snapshot The `MGLMapSnapshot` that was generated or `nil` if an error occurred. + @param error The error that occured or `nil` when successful. */ -typedef void (^MGLMapSnapshotCompletionHandler)(NSImage* _Nullable snapshot, NSError* _Nullable error); -#endif +typedef void (^MGLMapSnapshotCompletionHandler)(MGLMapSnapshot* _Nullable snapshot, NSError* _Nullable error); /** An immutable utility object for capturing map-based images. @@ -94,20 +113,18 @@ typedef void (^MGLMapSnapshotCompletionHandler)(NSImage* _Nullable snapshot, NSE ### Example ```swift - var camera = MGLMapCamera() - camera.centerCoordinate = CLLocationCoordinate2D(latitude: 37.7184, longitude: -122.4365) - camera.pitch = 20 + let camera = MGLMapCamera(lookingAtCenter: CLLocationCoordinate2D(latitude: 37.7184, longitude: -122.4365), fromDistance: 100, pitch: 20, heading: 0) - var options = MGLMapSnapshotOptions(styleURL: MGLStyle.satelliteStreetsStyleURL(), camera: camera, size: CGSize(width: 320, height: 480)) + let options = MGLMapSnapshotOptions(styleURL: MGLStyle.satelliteStreetsStyleURL(), camera: camera, size: CGSize(width: 320, height: 480)) options.zoomLevel = 10 - var snapshotter = MGLMapSnapshotter(options: options) - snapshotter.start { (image, error) in - if error { - // error handler - } else { - // image handler - } + let snapshotter = MGLMapSnapshotter(options: options) + snapshotter.start { (snapshot, error) in + if error != nil { + // error handler + } else { + // image handler + } } ``` */ @@ -142,7 +159,8 @@ MGL_EXPORT /** The zoom level. - The default zoom level is 0. This overwrites the camera zoom level if set. + The default zoom level is 0. If this property is non-zero and the camera property + is non-nil, the camera’s altitude is ignored in favor of this property’s value. */ @property (nonatomic) double zoomLevel; @@ -170,7 +188,7 @@ MGL_EXPORT map ID (`mapbox://styles/{user}/{style`}), or a path to a local file relative to the application’s resource path. Specify `nil` for the default style. */ -@property (nonatomic) NSURL* styleURL; +@property (nonatomic, nullable) NSURL *styleURL; /** The size of the output image, measured in points. diff --git a/platform/darwin/src/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm index 9d32ecf72c..193548ac11 100644 --- a/platform/darwin/src/MGLMapSnapshotter.mm +++ b/platform/darwin/src/MGLMapSnapshotter.mm @@ -49,6 +49,33 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; @end +@interface MGLMapSnapshot() +- (instancetype)initWithImage:(nullable MGLImage *)image scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn; + +@property (nonatomic) CGFloat scale; +@end + +@implementation MGLMapSnapshot { + mbgl::MapSnapshotter::PointForFn _pointForFn; +} +- (instancetype)initWithImage:(nullable MGLImage *)image scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn +{ + self = [super init]; + if (self) { + _pointForFn = std::move(pointForFn); + _scale = scale; + _image = image; + } + return self; +} + +- (CGPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate +{ + mbgl::ScreenCoordinate sc = _pointForFn(MGLLatLngFromLocationCoordinate2D(coordinate)); + return CGPointMake(sc.x * self.scale, sc.y * self.scale); +} +@end + @interface MGLMapSnapshotter() @property (nonatomic) MGLMapSnapshotOptions *options; @end @@ -117,7 +144,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; _loading = true; dispatch_async(queue, ^{ - _snapshotCallback = std::make_unique>(*mbgl::Scheduler::GetCurrent(), [=](std::exception_ptr mbglError, mbgl::PremultipliedImage image) { + _snapshotCallback = std::make_unique>(*mbgl::Scheduler::GetCurrent(), [=](std::exception_ptr mbglError, mbgl::PremultipliedImage image, mbgl::MapSnapshotter::PointForFn pointForFn) { _loading = false; if (mbglError) { NSString *description = @(mbgl::util::toString(mbglError).c_str()); @@ -171,7 +198,8 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; // Dispatch result to origin queue dispatch_async(queue, ^{ - completion(compositedImage, nil); + MGLMapSnapshot* snapshot = [[MGLMapSnapshot alloc] initWithImage:compositedImage scale:self.options.scale pointForFn:pointForFn]; + completion(snapshot, nil); }); }); } @@ -189,7 +217,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; - (NSURL *)styleURL { NSString *styleURLString = @(_mbglMapSnapshotter->getStyleURL().c_str()); - return styleURLString && styleURLString.length > 0 ? [NSURL URLWithString:styleURLString] : nil; + return styleURLString.length ? [NSURL URLWithString:styleURLString] : nil; } - (void)setStyleURL:(NSURL *)url diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift index 42c656f203..8762af9ba4 100644 --- a/platform/darwin/test/MGLDocumentationExampleTests.swift +++ b/platform/darwin/test/MGLDocumentationExampleTests.swift @@ -278,6 +278,24 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate { //#-end-example-code } + func testMGLMapSnapshotter() { + //#-example-code + let camera = MGLMapCamera(lookingAtCenter: CLLocationCoordinate2D(latitude: 37.7184, longitude: -122.4365), fromDistance: 100, pitch: 20, heading: 0) + + let options = MGLMapSnapshotOptions(styleURL: MGLStyle.satelliteStreetsStyleURL(), camera: camera, size: CGSize(width: 320, height: 480)) + options.zoomLevel = 10 + + let snapshotter = MGLMapSnapshotter(options: options) + snapshotter.start { (snapshot, error) in + if error != nil { + // error handler + } else { + // image handler + } + } + //#-end-example-code + } + // For testMGLMapView(). func myCustomFunction() {} } diff --git a/platform/ios/app/MBXSnapshotsViewController.m b/platform/ios/app/MBXSnapshotsViewController.m index ab5ad97c90..3bf93d8721 100644 --- a/platform/ios/app/MBXSnapshotsViewController.m +++ b/platform/ios/app/MBXSnapshotsViewController.m @@ -51,11 +51,11 @@ // Create and start the snapshotter MGLMapSnapshotter* snapshotter = [[MGLMapSnapshotter alloc] initWithOptions:options]; - [snapshotter startWithCompletionHandler: ^(UIImage *image, NSError *error) { + [snapshotter startWithCompletionHandler: ^(MGLMapSnapshot* snapshot, NSError *error) { if (error) { NSLog(@"Could not load snapshot: %@", [error localizedDescription]); } else { - imageView.image = image; + imageView.image = snapshot.image; } }]; diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m index feef53062b..0df6b10518 100644 --- a/platform/macos/app/MapDocument.m +++ b/platform/macos/app/MapDocument.m @@ -167,7 +167,7 @@ NS_ARRAY_OF(id ) *MBXFlattenedShapes(NS_ARRAY_OF(id ) *MBXFlattenedShapes(NS_ARRAY_OF(id ) *MBXFlattenedShapes(NS_ARRAY_OF(id