summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Rex <julian.rex@mapbox.com>2018-06-27 10:08:16 -0400
committerTobrun <tobrun@mapbox.com>2018-07-05 18:50:21 +0200
commit56ab3318a300b3675e902fd13690252d87739a27 (patch)
treef3717f3272ac1e5c93a390135df8c7c8715daa00
parent99f9787cc4099b76401ab5b9a9ef7d2f894f9ab6 (diff)
downloadqtlocation-mapboxgl-56ab3318a300b3675e902fd13690252d87739a27.tar.gz
[ios] [macos] Added `-[MGLSnapshot coordinateForPoint:]` and associated test.
-rw-r--r--platform/darwin/src/MGLMapSnapshotter.h11
-rw-r--r--platform/darwin/src/MGLMapSnapshotter.mm51
-rw-r--r--platform/ios/CHANGELOG.md4
-rw-r--r--platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m90
-rw-r--r--platform/macos/CHANGELOG.md1
5 files changed, 149 insertions, 8 deletions
diff --git a/platform/darwin/src/MGLMapSnapshotter.h b/platform/darwin/src/MGLMapSnapshotter.h
index 976213c8ba..a5ddcac0ac 100644
--- a/platform/darwin/src/MGLMapSnapshotter.h
+++ b/platform/darwin/src/MGLMapSnapshotter.h
@@ -86,6 +86,11 @@ MGL_EXPORT
- (CGPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate;
/**
+ Converts the specified image point to a map coordinate.
+ */
+- (CLLocationCoordinate2D)coordinateForPoint:(CGPoint)point;
+
+/**
The image of the map’s content.
*/
@property (nonatomic, readonly) UIImage *image;
@@ -97,6 +102,12 @@ MGL_EXPORT
- (NSPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate;
/**
+ Converts the specified image point to a map coordinate.
+ */
+- (CLLocationCoordinate2D)coordinateForPoint:(NSPoint)point;
+
+
+/**
The image of the map’s content.
*/
@property (nonatomic, readonly) NSImage *image;
diff --git a/platform/darwin/src/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm
index d9fa044217..d9d16cc5be 100644
--- a/platform/darwin/src/MGLMapSnapshotter.mm
+++ b/platform/darwin/src/MGLMapSnapshotter.mm
@@ -53,31 +53,59 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
@end
@interface MGLMapSnapshot()
-- (instancetype)initWithImage:(nullable MGLImage *)image scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn;
+- (instancetype)initWithImage:(nullable MGLImage *)image scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn;
@property (nonatomic) CGFloat scale;
@end
@implementation MGLMapSnapshot {
mbgl::MapSnapshotter::PointForFn _pointForFn;
+ mbgl::MapSnapshotter::LatLngForFn _latLngForFn;
}
-- (instancetype)initWithImage:(nullable MGLImage *)image scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn
+- (instancetype)initWithImage:(nullable MGLImage *)image scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn
{
self = [super init];
if (self) {
_pointForFn = std::move(pointForFn);
+ _latLngForFn = std::move(latLngForFn);
_scale = scale;
_image = image;
}
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));
+ return NSMakePoint(sc.x, self.image.size.height - sc.y);
+}
+
+- (CLLocationCoordinate2D)coordinateForPoint:(NSPoint)point
+{
+ auto screenCoord = mbgl::ScreenCoordinate(point.x, self.image.size.height - point.y);
+ mbgl::LatLng latLng = _latLngForFn(screenCoord);
+ return MGLLocationCoordinate2DFromLatLng(latLng);
+}
+
+#endif
+
@end
@interface MGLMapSnapshotter()
@@ -123,7 +151,11 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
__weak __typeof__(self) weakSelf = self;
// mbgl::Scheduler::GetCurrent() scheduler means "run callback on current (ie UI/main) thread"
// capture weakSelf to avoid retain cycle if callback is never called (ie snapshot cancelled)
- _snapshotCallback = std::make_unique<mbgl::Actor<mbgl::MapSnapshotter::Callback>>(*mbgl::Scheduler::GetCurrent(), [=](std::exception_ptr mbglError, mbgl::PremultipliedImage image, mbgl::MapSnapshotter::Attributions attributions, mbgl::MapSnapshotter::PointForFn pointForFn) {
+
+ _snapshotCallback = std::make_unique<mbgl::Actor<mbgl::MapSnapshotter::Callback>>(
+ *mbgl::Scheduler::GetCurrent(),
+ [=](std::exception_ptr mbglError, mbgl::PremultipliedImage image, mbgl::MapSnapshotter::Attributions attributions, mbgl::MapSnapshotter::PointForFn pointForFn, mbgl::MapSnapshotter::LatLngForFn latLngForFn) {
+
__typeof__(self) strongSelf = weakSelf;
// If self had died, _snapshotCallback would have been destroyed and this block would not be executed
NSCAssert(strongSelf, @"Snapshot callback executed after being destroyed.");
@@ -147,7 +179,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
mglImage.size = NSMakeSize(mglImage.size.width / strongSelf.options.scale,
mglImage.size.height / strongSelf.options.scale);
#endif
- [strongSelf drawAttributedSnapshot:attributions snapshotImage:mglImage pointForFn:pointForFn queue:queue completionHandler:completion];
+ [strongSelf drawAttributedSnapshot:attributions snapshotImage:mglImage pointForFn:pointForFn latLngForFn:latLngForFn queue:queue completionHandler:completion];
}
strongSelf->_snapshotCallback = NULL;
});
@@ -158,7 +190,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
_mbglMapSnapshotter->snapshot(_snapshotCallback->self());
}
-+ (void)drawAttributedSnapshotWorker:(mbgl::MapSnapshotter::Attributions)attributions snapshotImage:(MGLImage *)mglImage pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn queue:(dispatch_queue_t)queue scale:(CGFloat)scale size:(CGSize)size completionHandler:(MGLMapSnapshotCompletionHandler)completion {
++ (void)drawAttributedSnapshotWorker:(mbgl::MapSnapshotter::Attributions)attributions snapshotImage:(MGLImage *)mglImage pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn queue:(dispatch_queue_t)queue scale:(CGFloat)scale size:(CGSize)size completionHandler:(MGLMapSnapshotCompletionHandler)completion {
NSArray<MGLAttributionInfo *>* attributionInfo = [MGLMapSnapshotter generateAttributionInfos:attributions];
@@ -282,12 +314,15 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
#endif
// Dispatch result to origin queue
dispatch_async(queue, ^{
- MGLMapSnapshot* snapshot = [[MGLMapSnapshot alloc] initWithImage:compositedImage scale:scale pointForFn:pointForFn];
+ MGLMapSnapshot* snapshot = [[MGLMapSnapshot alloc] initWithImage:compositedImage
+ scale:scale
+ pointForFn:pointForFn
+ latLngForFn:latLngForFn];
completion(snapshot, nil);
});
}
-- (void)drawAttributedSnapshot:(mbgl::MapSnapshotter::Attributions)attributions snapshotImage:(MGLImage *)mglImage pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn queue:(dispatch_queue_t)queue completionHandler:(MGLMapSnapshotCompletionHandler)completion {
+- (void)drawAttributedSnapshot:(mbgl::MapSnapshotter::Attributions)attributions snapshotImage:(MGLImage *)mglImage pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn queue:(dispatch_queue_t)queue completionHandler:(MGLMapSnapshotCompletionHandler)completion {
// Process image watermark in a work queue
dispatch_queue_t workQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
@@ -297,7 +332,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
// pointForFn is a copyable std::function that captures state by value: see MapSnapshotter::Impl::snapshot
dispatch_async(workQueue, ^{
// Call a class method to ensure we're not accidentally capturing self
- [MGLMapSnapshotter drawAttributedSnapshotWorker:attributions snapshotImage:mglImage pointForFn:pointForFn queue:queue scale:scale size:size completionHandler:completion];
+ [MGLMapSnapshotter drawAttributedSnapshotWorker:attributions snapshotImage:mglImage pointForFn:pointForFn latLngForFn:latLngForFn queue:queue scale:scale size:size completionHandler:completion];
});
}
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index 4d052e0269..f69000a600 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -21,6 +21,10 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Improved caching performance. ([#12072](https://github.com/mapbox/mapbox-gl-native/pull/12072))
+### Other changes
+
+* Added `-[MGLMapSnapshot coordinateForPoint:]` that returns a map coordinate for a specified snapshot image point. ([#12221](https://github.com/mapbox/mapbox-gl-native/pull/12221))
+
## 4.0.3 - June 22, 2018
* Fixed a crash in `-[MGLStyle localizeLabelsIntoLocale:]` on iOS 9._x_. ([#12123](https://github.com/mapbox/mapbox-gl-native/pull/12123))
diff --git a/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m b/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m
index 6a698121c9..22f7fc5911 100644
--- a/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m
+++ b/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m
@@ -234,4 +234,94 @@ NSString* validAccessToken() {
[self waitForExpectations:@[expectation] timeout:60.0];
}
+- (void)testSnapshotPointConversion {
+ if (!validAccessToken()) {
+ return;
+ }
+
+ CGSize size = self.mapView.bounds.size;
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot"];
+ expectation.expectedFulfillmentCount = 1;
+ expectation.assertForOverFulfill = YES;
+
+ CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0);
+
+ MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size);
+ XCTAssertNotNil(snapshotter);
+
+ __weak __typeof__(self) weakself = self;
+
+ [snapshotter startWithCompletionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) {
+
+ __typeof__(self) myself = weakself;
+
+ MGLTestAssertNotNil(myself, snapshot);
+
+ CGPoint point = [snapshot pointForCoordinate:coord];
+
+ CGFloat epsilon = 0.000001;
+
+ MGLTestAssertEqualWithAccuracy(myself, point.x, size.width/2.0, epsilon);
+ MGLTestAssertEqualWithAccuracy(myself, point.y, size.height/2.0, epsilon);
+
+ CLLocationCoordinate2D coord2 = [snapshot coordinateForPoint:point];
+
+ MGLTestAssertEqualWithAccuracy(myself, coord.latitude, coord2.latitude, epsilon);
+ MGLTestAssertEqualWithAccuracy(myself, coord.longitude, coord2.longitude, epsilon);
+
+ [expectation fulfill];
+ }];
+
+ [self waitForExpectations:@[expectation] timeout:5.0];
+}
+
+- (void)testSnapshotPointConversionCoordinateOrdering {
+ if (!validAccessToken()) {
+ return;
+ }
+
+ CGSize size = self.mapView.bounds.size;
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot"];
+ expectation.expectedFulfillmentCount = 1;
+ expectation.assertForOverFulfill = YES;
+
+ CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0);
+
+ MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size);
+ XCTAssertNotNil(snapshotter);
+
+ __weak __typeof__(self) weakself = self;
+
+ [snapshotter startWithCompletionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) {
+
+ __typeof__(self) myself = weakself;
+
+ CGFloat epsilon = 0.000001;
+
+ MGLTestAssertNotNil(myself, snapshot);
+
+ CLLocationCoordinate2D coordTL = [snapshot coordinateForPoint:CGPointZero];
+
+ MGLTestAssert(myself, coordTL.longitude < coord.longitude);
+ MGLTestAssert(myself, coordTL.latitude > coord.latitude);
+
+ // And check point
+ CGPoint tl = [snapshot pointForCoordinate:coordTL];
+ MGLTestAssertEqualWithAccuracy(myself, tl.x, 0.0, epsilon);
+ MGLTestAssertEqualWithAccuracy(myself, tl.y, 0.0, epsilon);
+
+ CLLocationCoordinate2D coordBR = [snapshot coordinateForPoint:CGPointMake(size.width, size.height)];
+
+ MGLTestAssert(myself, coordBR.longitude > coord.longitude);
+ MGLTestAssert(myself, coordBR.latitude < coord.latitude);
+
+ [expectation fulfill];
+ }];
+
+ [self waitForExpectations:@[expectation] timeout:5.0];
+}
+
+
@end
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index e12ac427d8..d9615f97e7 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -4,6 +4,7 @@
* Added `-[MGLMapView camera:fittingShape:edgePadding:]` and `-[MGLMapView camera:fittingCoordinateBounds:edgePadding:]` allowing you specify the pitch and direction for the calculated camera. ([#12213](https://github.com/mapbox/mapbox-gl-native/pull/12213))
* `-[MGLStyle localizeLabelsIntoLocale:]` and `-[NSExpression mgl_expressionLocalizedIntoLocale:]` can automatically localize labels into Japanese or Korean based on the system’s language settings. ([#12286](https://github.com/mapbox/mapbox-gl-native/pull/12286))
+* Added `-[MGLMapSnapshot coordinateForPoint:]` that returns a map coordinate for a specified snapshot image point. Fixed a bug in `-[MGLMapShapshot pointForCoordinate:]` where incorrect points were returned. ([#12221](https://github.com/mapbox/mapbox-gl-native/pull/12221))
## 0.7.2 - June 22, 2018