[ios] Adds pointForCoordinate/coordinateForPoint to MGLMapSnapshotOverlay (#15746)

* [ios] Adds `pointForCoordinate:`/`coordinateForPoint:` to MGLMapSnapshotOverlay

* [ios] Adds PR #

* [ios, macos] Update file lists & mac contexts

* [macos] Fix for image scale in overlay.

* [ios] Updated change log based on PR feedback.
This commit is contained in:
Julian Rex
2019-10-04 13:51:40 -04:00
committed by GitHub
parent 910e34b855
commit 33a70100b8
7 changed files with 177 additions and 12 deletions

View File

@@ -19,6 +19,31 @@ MGL_EXPORT
*/
@property (nonatomic, readonly) CGContextRef context;
#if TARGET_OS_IPHONE
/**
Converts the specified map coordinate to a point in the coordinate space of the
context.
*/
- (CGPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate;
/**
Converts the specified context point to a map coordinate.
*/
- (CLLocationCoordinate2D)coordinateForPoint:(CGPoint)point;
#else
/**
Converts the specified map coordinate to a point in the coordinate space of the
context.
*/
- (NSPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate;
/**
Converts the specified context point to a map coordinate.
*/
- (CLLocationCoordinate2D)coordinateForPoint:(NSPoint)point;
#endif
@end
/**

View File

@@ -17,6 +17,8 @@
#import "MGLAttributionInfo_Private.h"
#import "MGLLoggingConfiguration_Private.h"
#import "MGLRendererConfiguration.h"
#import "MGLMapSnapshotter_Private.h"
#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
#import "MGLMapboxEvents.h"
#endif
@@ -33,23 +35,61 @@ const CGPoint MGLLogoImagePosition = CGPointMake(8, 8);
const CGFloat MGLSnapshotterMinimumPixelSize = 64;
@interface MGLMapSnapshotOverlay()
- (instancetype)initWithContext:(CGContextRef)context;
@interface MGLMapSnapshotOverlay() <MGLMapSnapshotProtocol>
@property (nonatomic, assign) CGFloat scale;
- (instancetype)initWithContext:(CGContextRef)context scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn;
@end
@implementation MGLMapSnapshotOverlay
@implementation MGLMapSnapshotOverlay {
mbgl::MapSnapshotter::PointForFn _pointForFn;
mbgl::MapSnapshotter::LatLngForFn _latLngForFn;
}
- (instancetype) initWithContext:(CGContextRef)context {
- (instancetype) initWithContext:(CGContextRef)context scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn {
self = [super init];
if (self) {
_context = context;
_scale = scale;
_pointForFn = pointForFn;
_latLngForFn = latLngForFn;
}
return self;
}
#if TARGET_OS_IPHONE
- (CGPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate
{
mbgl::ScreenCoordinate sc = _pointForFn(MGLLatLngFromLocationCoordinate2D(coordinate));
return CGPointMake(sc.x, sc.y);
}
- (CLLocationCoordinate2D)coordinateForPoint:(CGPoint)point
{
mbgl::LatLng latLng = _latLngForFn(mbgl::ScreenCoordinate(point.x, point.y));
return MGLLocationCoordinate2DFromLatLng(latLng);
}
#else
- (NSPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate
{
mbgl::ScreenCoordinate sc = _pointForFn(MGLLatLngFromLocationCoordinate2D(coordinate));
CGFloat height = ((CGFloat)CGBitmapContextGetHeight(self.context))/self.scale;
return NSMakePoint(sc.x, height - sc.y);
}
- (CLLocationCoordinate2D)coordinateForPoint:(NSPoint)point
{
CGFloat height = ((CGFloat)CGBitmapContextGetHeight(self.context))/self.scale;
auto screenCoord = mbgl::ScreenCoordinate(point.x, height - point.y);
mbgl::LatLng latLng = _latLngForFn(screenCoord);
return MGLLocationCoordinate2DFromLatLng(latLng);
}
#endif
@end
@implementation MGLMapSnapshotOptions
@@ -78,7 +118,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
@end
@interface MGLMapSnapshot()
@interface MGLMapSnapshot() <MGLMapSnapshotProtocol>
- (instancetype)initWithImage:(nullable MGLImage *)image scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn;
@property (nonatomic) CGFloat scale;
@@ -93,8 +133,8 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
{
self = [super init];
if (self) {
_pointForFn = std::move(pointForFn);
_latLngForFn = std::move(latLngForFn);
_pointForFn = pointForFn;
_latLngForFn = latLngForFn;
_scale = scale;
_image = image;
}
@@ -328,7 +368,10 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
CGContextRef currentContext = UIGraphicsGetCurrentContext();
if (currentContext && overlayHandler) {
MGLMapSnapshotOverlay *snapshotOverlay = [[MGLMapSnapshotOverlay alloc] initWithContext:currentContext];
MGLMapSnapshotOverlay *snapshotOverlay = [[MGLMapSnapshotOverlay alloc] initWithContext:currentContext
scale:scale
pointForFn:pointForFn
latLngForFn:latLngForFn];
CGContextSaveGState(snapshotOverlay.context);
overlayHandler(snapshotOverlay);
CGContextRestoreGState(snapshotOverlay.context);
@@ -409,7 +452,10 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
if (currentContext && overlayHandler) {
MGLMapSnapshotOverlay *snapshotOverlay = [[MGLMapSnapshotOverlay alloc] initWithContext:currentContext.CGContext];
MGLMapSnapshotOverlay *snapshotOverlay = [[MGLMapSnapshotOverlay alloc] initWithContext:currentContext.CGContext
scale:scale
pointForFn:pointForFn
latLngForFn:latLngForFn];
[currentContext saveGraphicsState];
overlayHandler(snapshotOverlay);
[currentContext restoreGraphicsState];

View File

@@ -0,0 +1,14 @@
#import "MGLMapSnapshotter.h"
@protocol MGLMapSnapshotProtocol <NSObject>
#if TARGET_OS_IPHONE
- (CGPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate;
- (CLLocationCoordinate2D)coordinateForPoint:(CGPoint)point;
#else
- (NSPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate;
- (CLLocationCoordinate2D)coordinateForPoint:(NSPoint)point;
#endif
@end

View File

@@ -12,6 +12,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
### Other changes
* Added `-[MGLMapSnapshotOverlay coordinateForPoint:]` and `-[MGLMapSnapshotOverlay pointForCoordinate:]` to convert between context and map coordinates, mirroring those of `MGLMapSnapshot`. ([#15746](https://github.com/mapbox/mapbox-gl-native/pull/15746))
* Suppress network requests for expired tiles update, if these tiles are invisible. ([#15741](https://github.com/mapbox/mapbox-gl-native/pull/15741))
* Fixed an issue that caused `MGLScaleBar` to have an incorrect size when resizing or rotating. ([#15703](https://github.com/mapbox/mapbox-gl-native/pull/15703))

View File

@@ -1,4 +1,5 @@
#import "MGLMapViewIntegrationTest.h"
#import "MGLMapSnapshotter_Private.h"
@interface MGLMapSnapshotter ()
@property (nonatomic) BOOL cancelled;
@@ -24,6 +25,21 @@ MGLMapSnapshotter* snapshotterWithCoordinates(CLLocationCoordinate2D coordinates
return snapshotter;
}
MGLMapSnapshotter* snapshotterWithBounds(MGLCoordinateBounds bounds, CGSize size) {
MGLMapCamera* mapCamera = [[MGLMapCamera alloc] init];
MGLMapSnapshotOptions* options = [[MGLMapSnapshotOptions alloc] initWithStyleURL:[MGLStyle satelliteStreetsStyleURL]
camera:mapCamera
size:size];
options.coordinateBounds = bounds;
// Create and start the snapshotter
MGLMapSnapshotter* snapshotter = [[MGLMapSnapshotter alloc] initWithOptions:options];
return snapshotter;
}
@implementation MGLMapSnapshotterTest
- (void)testMultipleSnapshotsWithASingleSnapshotter🔒 {
@@ -462,4 +478,60 @@ MGLMapSnapshotter* snapshotterWithCoordinates(CLLocationCoordinate2D coordinates
[self waitForExpectations:@[expectation] timeout:10.0];
}
- (void)testSnapshotCoordinatesWithOverlayHandler🔒 {
CGSize size = self.mapView.bounds.size;
XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot with overlay succeeds"];
expectation.expectedFulfillmentCount = 2;
CLLocationCoordinate2D london = { .latitude = 51.5074, .longitude = -0.1278 };
CLLocationCoordinate2D paris = { .latitude = 48.8566, .longitude = 2.3522 };
MGLCoordinateBounds bounds = {
.ne = london,
.sw = paris
};
MGLMapSnapshotter *snapshotter = snapshotterWithBounds(bounds, size);
XCTAssertNotNil(snapshotter);
void (^testCoordinates)(id<MGLMapSnapshotProtocol>) = ^(id<MGLMapSnapshotProtocol> snapshot){
XCTAssertNotNil(snapshot);
CGPoint londonPoint = [snapshot pointForCoordinate:london];
CGPoint parisPoint = [snapshot pointForCoordinate:paris];
XCTAssertEqualWithAccuracy(londonPoint.x, 0, 0.1);
XCTAssertEqualWithAccuracy(parisPoint.x, size.width, 0.1);
// Vertically, London and Paris are inset (due to the size vs coordinate bounds)
XCTAssert(parisPoint.y > londonPoint.y);
XCTAssert(londonPoint.y > 0.0);
XCTAssert(parisPoint.y < size.height);
CLLocationCoordinate2D london2 = [snapshot coordinateForPoint:londonPoint];
CLLocationCoordinate2D paris2 = [snapshot coordinateForPoint:parisPoint];
XCTAssertEqualWithAccuracy(london.latitude, london2.latitude, 0.0000001);
XCTAssertEqualWithAccuracy(london.longitude, london2.longitude, 0.0000001);
XCTAssertEqualWithAccuracy(paris.latitude, paris2.latitude, 0.0000001);
XCTAssertEqualWithAccuracy(paris.longitude, paris2.longitude, 0.0000001);
};
[snapshotter startWithOverlayHandler:^(MGLMapSnapshotOverlay *snapshotOverlay) {
XCTAssert([snapshotOverlay conformsToProtocol:@protocol(MGLMapSnapshotProtocol)]);
testCoordinates((id<MGLMapSnapshotProtocol>)snapshotOverlay);
[expectation fulfill];
} completionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) {
XCTAssert([snapshot conformsToProtocol:@protocol(MGLMapSnapshotProtocol)]);
testCoordinates((id<MGLMapSnapshotProtocol>)snapshot);
[expectation fulfill];
}];
[self waitForExpectations:@[expectation] timeout:10.0];
}
@end

View File

@@ -528,6 +528,8 @@
CABE5DAD2072FAB40003AF3C /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA8847D21CBAF91600AB86E3 /* Mapbox.framework */; };
CAD9D0AA22A86D6F001B25EE /* MGLResourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CAD9D0A922A86D6F001B25EE /* MGLResourceTests.mm */; };
CAE7AD5520F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAE7AD5420F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift */; };
CAFB3C14234505D500399265 /* MGLMapSnapshotter_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = CAFB3C13234505D500399265 /* MGLMapSnapshotter_Private.h */; };
CAFB3C15234505D500399265 /* MGLMapSnapshotter_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = CAFB3C13234505D500399265 /* MGLMapSnapshotter_Private.h */; };
CF75A91522D85E860058A5C4 /* MGLLoggingConfiguration.mm in Sources */ = {isa = PBXBuildFile; fileRef = CF75A91422D85E860058A5C4 /* MGLLoggingConfiguration.mm */; };
CF75A91622D85E860058A5C4 /* MGLLoggingConfiguration.mm in Sources */ = {isa = PBXBuildFile; fileRef = CF75A91422D85E860058A5C4 /* MGLLoggingConfiguration.mm */; };
DA00FC8E1D5EEB0D009AABC8 /* MGLAttributionInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA00FC8C1D5EEB0D009AABC8 /* MGLAttributionInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -1072,8 +1074,8 @@
5580B45A229570A10091291B /* MGLMapView+OpenGL.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "MGLMapView+OpenGL.mm"; sourceTree = "<group>"; };
558DE79E1E5615E400C7916D /* MGLFoundation_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFoundation_Private.h; sourceTree = "<group>"; };
558DE79F1E5615E400C7916D /* MGLFoundation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFoundation.mm; sourceTree = "<group>"; };
55CF752E213ED92000ED86C4 /* libmbgl-vendor-icu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libmbgl-vendor-icu.a; sourceTree = BUILT_PRODUCTS_DIR; };
55CF7530213ED92A00ED86C4 /* libmbgl-vendor-icu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libmbgl-vendor-icu.a; sourceTree = BUILT_PRODUCTS_DIR; };
55CF752E213ED92000ED86C4 /* libmbgl-vendor-icu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libmbgl-vendor-icu.a"; sourceTree = BUILT_PRODUCTS_DIR; };
55CF7530213ED92A00ED86C4 /* libmbgl-vendor-icu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libmbgl-vendor-icu.a"; sourceTree = BUILT_PRODUCTS_DIR; };
55D120A71F791007004B6D81 /* libmbgl-loop-darwin.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libmbgl-loop-darwin.a"; sourceTree = BUILT_PRODUCTS_DIR; };
55D120A91F79100C004B6D81 /* libmbgl-filesource.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libmbgl-filesource.a"; sourceTree = BUILT_PRODUCTS_DIR; };
55D8C9941D0F133500F42F10 /* config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = config.xcconfig; path = ../../build/ios/config.xcconfig; sourceTree = "<group>"; };
@@ -1218,6 +1220,7 @@
CAD9D0A922A86D6F001B25EE /* MGLResourceTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLResourceTests.mm; path = ../../darwin/test/MGLResourceTests.mm; sourceTree = "<group>"; };
CAE7AD5320F46EF5003B6782 /* integration-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "integration-Bridging-Header.h"; sourceTree = "<group>"; };
CAE7AD5420F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MGLMapSnapshotterSwiftTests.swift; sourceTree = "<group>"; };
CAFB3C13234505D500399265 /* MGLMapSnapshotter_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLMapSnapshotter_Private.h; sourceTree = "<group>"; };
CF75A91422D85E860058A5C4 /* MGLLoggingConfiguration.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLLoggingConfiguration.mm; sourceTree = "<group>"; };
DA00FC8C1D5EEB0D009AABC8 /* MGLAttributionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo.h; sourceTree = "<group>"; };
DA00FC8D1D5EEB0D009AABC8 /* MGLAttributionInfo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAttributionInfo.mm; sourceTree = "<group>"; };
@@ -2151,6 +2154,7 @@
DA8847E21CBAFA5100AB86E3 /* MGLMapCamera.h */,
DA8848031CBAFA6200AB86E3 /* MGLMapCamera.mm */,
927FBCFD1F4DB05500F8BF1F /* MGLMapSnapshotter.h */,
CAFB3C13234505D500399265 /* MGLMapSnapshotter_Private.h */,
927FBCFE1F4DB05500F8BF1F /* MGLMapSnapshotter.mm */,
DD0902A41DB18F1B00C5BDCE /* MGLNetworkConfiguration.h */,
1F2B94BF221636D800210640 /* MGLNetworkConfiguration_Private.h */,
@@ -2529,6 +2533,7 @@
1F6A82A221360F9D00BA5B41 /* MGLLoggingConfiguration.h in Headers */,
DA8848311CBAFA6200AB86E3 /* NSString+MGLAdditions.h in Headers */,
967C864B210A9D3C004DF794 /* UIDevice+MGLAdditions.h in Headers */,
CAFB3C14234505D500399265 /* MGLMapSnapshotter_Private.h in Headers */,
1FCAE2A220B872A400C577DD /* MGLLocationManager.h in Headers */,
DACA86262019218600E9693A /* MGLRasterDEMSource.h in Headers */,
353933F81D3FB79F003F57D7 /* MGLLineStyleLayer.h in Headers */,
@@ -2722,6 +2727,7 @@
35E1A4D91D74336F007AA97F /* MGLValueEvaluator.h in Headers */,
DABFB8701CBE9A0F00D62B32 /* MGLMapView+IBAdditions.h in Headers */,
9C6E283822A982670056B7BE /* MMEEventLogger.h in Headers */,
CAFB3C15234505D500399265 /* MGLMapSnapshotter_Private.h in Headers */,
6F018BAF220031BF003E7269 /* UIView+MGLAdditions.h in Headers */,
96E516EA2000560B00A02306 /* MGLAnnotationView_Private.h in Headers */,
96E516FB20005A4000A02306 /* MGLUserLocationHeadingBeamLayer.h in Headers */,

View File

@@ -243,6 +243,7 @@
"MMEDate.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEDate.h",
"NSString+MGLAdditions.h": "platform/darwin/src/NSString+MGLAdditions.h",
"UIDevice+MGLAdditions.h": "platform/ios/src/UIDevice+MGLAdditions.h",
"MGLMapSnapshotter_Private.h": "platform/darwin/src/MGLMapSnapshotter_Private.h",
"MGLRendererFrontend.h": "platform/darwin/src/MGLRendererFrontend.h",
"MGLStyleValue_Private.h": "platform/darwin/src/MGLStyleValue_Private.h",
"MGLFillExtrusionStyleLayer_Private.h": "platform/darwin/src/MGLFillExtrusionStyleLayer_Private.h",