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

Commit

Permalink
[ios] [macos] Added -[MGLSnapshot coordinateForPoint:] and associat…
Browse files Browse the repository at this point in the history
…ed test.
  • Loading branch information
Julian Rex authored and tobrun committed Jul 5, 2018
1 parent 99f9787 commit 56ab331
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 8 deletions.
11 changes: 11 additions & 0 deletions platform/darwin/src/MGLMapSnapshotter.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,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.
*/
Expand All @@ -96,6 +101,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.
*/
Expand Down
51 changes: 43 additions & 8 deletions platform/darwin/src/MGLMapSnapshotter.mm
Original file line number Diff line number Diff line change
Expand Up @@ -53,31 +53,59 @@ - (instancetype _Nonnull)initWithStyleURL:(nullable NSURL *)styleURL camera:(MGL
@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()
Expand Down Expand Up @@ -123,7 +151,11 @@ - (void)startWithQueue:(dispatch_queue_t)queue completionHandler:(MGLMapSnapshot
__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.");
Expand All @@ -147,7 +179,7 @@ - (void)startWithQueue:(dispatch_queue_t)queue completionHandler:(MGLMapSnapshot
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;
});
Expand All @@ -158,7 +190,7 @@ - (void)startWithQueue:(dispatch_queue_t)queue completionHandler:(MGLMapSnapshot
_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];

Expand Down Expand Up @@ -282,12 +314,15 @@ + (void)drawAttributedSnapshotWorker:(mbgl::MapSnapshotter::Attributions)attribu
#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);
Expand All @@ -297,7 +332,7 @@ - (void)drawAttributedSnapshot:(mbgl::MapSnapshotter::Attributions)attributions
// 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];
});
}

Expand Down
4 changes: 4 additions & 0 deletions platform/ios/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,4 +234,94 @@ - (void)testMultipleSnapshottersPENDING {
[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
1 change: 1 addition & 0 deletions platform/macos/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit 56ab331

Please sign in to comment.