From cd4611dfefccbcc102f1ce0848a40e85d4c1ce60 Mon Sep 17 00:00:00 2001 From: Nadia Barbosa Date: Tue, 28 Aug 2018 08:52:27 -0700 Subject: [ios, macos] Allow -convertCoordinateBounds to span antimeridian --- platform/darwin/test/MGLMapViewTests.m | 42 ++++++++++++++++++++++++++ platform/ios/CHANGELOG.md | 1 + platform/ios/ios.xcodeproj/project.pbxproj | 4 +++ platform/ios/src/MGLMapView.h | 10 ++++-- platform/ios/src/MGLMapView.mm | 27 +++++++++++++---- platform/macos/CHANGELOG.md | 1 + platform/macos/macos.xcodeproj/project.pbxproj | 4 +++ platform/macos/src/MGLMapView.h | 5 +++ platform/macos/src/MGLMapView.mm | 26 +++++++++++++--- 9 files changed, 107 insertions(+), 13 deletions(-) create mode 100644 platform/darwin/test/MGLMapViewTests.m diff --git a/platform/darwin/test/MGLMapViewTests.m b/platform/darwin/test/MGLMapViewTests.m new file mode 100644 index 0000000000..6ac8e1fe81 --- /dev/null +++ b/platform/darwin/test/MGLMapViewTests.m @@ -0,0 +1,42 @@ +#import +#import + +static MGLMapView *mapView; + +@interface MGLMapViewTests : XCTestCase + +@end + +@implementation MGLMapViewTests + ++ (void)setUp { + [super setUp]; + + [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"]; + mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 64, 64) styleURL:MGLStyle.streetsStyleURL]; + [mapView setCenterCoordinate:CLLocationCoordinate2DMake(33, 179)]; +} + +- (void)testCoordinateBoundsConversion { + MGLCoordinateBounds leftAntimeridianBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(-75, 175), CLLocationCoordinate2DMake(75, 180)); + CGRect leftAntimeridianBoundsRect = [mapView convertCoordinateBounds:leftAntimeridianBounds toRectToView:mapView]; + + MGLCoordinateBounds rightAntimeridianBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(-75, -180), CLLocationCoordinate2DMake(75, -175)); + CGRect rightAntimeridianBoundsRect = [mapView convertCoordinateBounds:rightAntimeridianBounds toRectToView:mapView]; + + MGLCoordinateBounds spanningBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(24, 140), CLLocationCoordinate2DMake(44, 240)); + CGRect spanningBoundsRect = [mapView convertCoordinateBounds:spanningBounds toRectToView:mapView]; + + // If the resulting CGRect from -convertCoordinateBounds:toRectToView: + // intersects the set of bounds to the left and right of the + // antimeridian, then we know that the CGRect spans across the antimeridian + XCTAssertTrue(CGRectIntersectsRect(spanningBoundsRect, leftAntimeridianBoundsRect), @"Resulting "); + XCTAssertTrue(CGRectIntersectsRect(spanningBoundsRect, rightAntimeridianBoundsRect), @"Something"); +} + ++ (void)tearDown { + mapView = nil; + [super tearDown]; +} + +@end diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 346ead2c3f..2ff02933e4 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -5,6 +5,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT ## master * Add support for feature expressions in `line-pattern`, `fill-pattern`, and `fill-extrusion-pattern` properties. [#12284](https://github.com/mapbox/mapbox-gl-native/pull/12284) +* Fixed an issue where `-[MGLMapView convertCoordinateBounds:toRectToView:]` would return an empty CGRect if the bounds crossed the antimeridian. ([#12758](https://github.com/mapbox/mapbox-gl-native/pull/12758)) ## 4.4.0 diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index 3875d46865..55e8a8ced3 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 071BBB031EE76146001FB02A /* MGLImageSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 071BBAFC1EE75CD4001FB02A /* MGLImageSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; 071BBB041EE76147001FB02A /* MGLImageSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 071BBAFC1EE75CD4001FB02A /* MGLImageSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; 071BBB071EE77631001FB02A /* MGLImageSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */; }; + 076171C32139C70900668A35 /* MGLMapViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 076171C22139C70900668A35 /* MGLMapViewTests.m */; }; 0778DD431F67556700A73B34 /* MGLComputedShapeSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 0778DD401F67555F00A73B34 /* MGLComputedShapeSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0778DD441F67556C00A73B34 /* MGLComputedShapeSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0778DD411F67555F00A73B34 /* MGLComputedShapeSource.mm */; }; 07D8C6FB1F67560100381808 /* MGLComputedShapeSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0778DD411F67555F00A73B34 /* MGLComputedShapeSource.mm */; }; @@ -752,6 +753,7 @@ 071BBAFC1EE75CD4001FB02A /* MGLImageSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLImageSource.h; sourceTree = ""; }; 071BBAFD1EE75CD4001FB02A /* MGLImageSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLImageSource.mm; sourceTree = ""; }; 071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLImageSourceTests.m; path = ../../darwin/test/MGLImageSourceTests.m; sourceTree = ""; }; + 076171C22139C70900668A35 /* MGLMapViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLMapViewTests.m; path = ../../darwin/test/MGLMapViewTests.m; sourceTree = ""; }; 0778DD401F67555F00A73B34 /* MGLComputedShapeSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLComputedShapeSource.h; sourceTree = ""; }; 0778DD411F67555F00A73B34 /* MGLComputedShapeSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLComputedShapeSource.mm; sourceTree = ""; }; 07D8C6FD1F67562800381808 /* MGLComputedShapeSourceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLComputedShapeSourceTests.m; path = ../../darwin/test/MGLComputedShapeSourceTests.m; sourceTree = ""; }; @@ -1879,6 +1881,7 @@ DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */, DA2E885C1CC0382C00F24E7B /* MGLGeometryTests.mm */, DA5DB1291FABF1EE001C2326 /* MGLMapAccessibilityElementTests.m */, + 076171C22139C70900668A35 /* MGLMapViewTests.m */, 16376B481FFEED010000563E /* MGLMapViewLayoutTests.m */, 9658C154204761FC00D8A674 /* MGLMapViewScaleBarTests.m */, 35E208A61D24210F00EC9A46 /* MGLNSDataAdditionsTests.m */, @@ -2915,6 +2918,7 @@ 357579801D501E09000B822E /* MGLFillStyleLayerTests.mm in Sources */, 35D9DDE21DA25EEC00DAAD69 /* MGLCodingTests.m in Sources */, DA1F8F3D1EBD287B00367E42 /* MGLDocumentationGuideTests.swift in Sources */, + 076171C32139C70900668A35 /* MGLMapViewTests.m in Sources */, 3598544D1E1D38AA00B29F84 /* MGLDistanceFormatterTests.m in Sources */, 071BBB071EE77631001FB02A /* MGLImageSourceTests.m in Sources */, DA2DBBCE1D51E80400D38FF9 /* MGLStyleLayerTests.m in Sources */, diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h index 20bfeeef39..02d146edcb 100644 --- a/platform/ios/src/MGLMapView.h +++ b/platform/ios/src/MGLMapView.h @@ -1118,8 +1118,9 @@ MGL_EXPORT IB_DESIGNABLE Converts a rectangle in the given view’s coordinate system to a geographic bounding box. - If a longitude is less than −180 degrees or greater than 180 degrees, the - bounding box straddles the antimeridian or international date line. + If the returned coordinate bounds contains a longitude is less than −180 degrees + or greater than 180 degrees, the bounding box straddles the antimeridian or + international date line. @param rect The rectangle to convert. @param view The view in whose coordinate system the rectangle is expressed. @@ -1130,6 +1131,11 @@ MGL_EXPORT IB_DESIGNABLE /** Converts a geographic bounding box to a rectangle in the given view’s coordinate system. + + To bring both sides of the antimeridian or international date line into view, + specify some longitudes less than −180 degrees or greater than 180 degrees. For + example, to show both Tokyo and San Francisco simultaneously, you could set the + visible bounds to extend from (35.68476, −220.24257) to (37.78428, −122.41310). @param bounds The geographic bounding box to convert. @param view The view in whose coordinate system the returned rectangle should diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 8ca41b328c..92d3724b03 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -3527,18 +3527,33 @@ public: - (CGRect)convertCoordinateBounds:(MGLCoordinateBounds)bounds toRectToView:(nullable UIView *)view { - if ( ! CLLocationCoordinate2DIsValid(bounds.sw) || ! CLLocationCoordinate2DIsValid(bounds.ne)) - { - return CGRectNull; - } return [self convertLatLngBounds:MGLLatLngBoundsFromCoordinateBounds(bounds) toRectToView:view]; } /// Converts a geographic bounding box to a rectangle in the view’s coordinate /// system. - (CGRect)convertLatLngBounds:(mbgl::LatLngBounds)bounds toRectToView:(nullable UIView *)view { - CGRect rect = { [self convertLatLng:bounds.southwest() toPointToView:view], CGSizeZero }; - rect = MGLExtendRect(rect, [self convertLatLng:bounds.northeast() toPointToView:view]); + auto northwest = bounds.northwest(); + auto northeast = bounds.northeast(); + auto southwest = bounds.southwest(); + auto southeast = bounds.southeast(); + + auto center = [self convertPoint:{ CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds) } toLatLngFromView:view]; + + // Extend bounds to account for the antimeridian + northwest.unwrapForShortestPath(center); + northeast.unwrapForShortestPath(center); + southwest.unwrapForShortestPath(center); + southeast.unwrapForShortestPath(center); + + auto correctedLatLngBounds = mbgl::LatLngBounds::empty(); + correctedLatLngBounds.extend(northwest); + correctedLatLngBounds.extend(northeast); + correctedLatLngBounds.extend(southwest); + correctedLatLngBounds.extend(southeast); + + CGRect rect = { [self convertLatLng:correctedLatLngBounds.southwest() toPointToView:view], CGSizeZero }; + rect = MGLExtendRect(rect, [self convertLatLng:correctedLatLngBounds.northeast() toPointToView:view]); return rect; } diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 78b7b74503..64a21534b0 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -8,6 +8,7 @@ * Added `MGLShapeOfflineRegion` for defining arbitrarily shaped offline regions [#11447](https://github.com/mapbox/mapbox-gl-native/pull/11447) * Added an `-[MGLMapViewDelegate mapView:shapeAnnotationIsEnabled:]` method to specify whether an annotation is selectable. ([#12352](https://github.com/mapbox/mapbox-gl-native/pull/12352)) * Add support for feature expressions in `line-pattern`, `fill-pattern`, and `fill-extrusion-pattern` properties. [#12284](https://github.com/mapbox/mapbox-gl-native/pull/12284) +* Fixed an issue where `-[MGLMapView convertCoordinateBounds:toRectToView:]` would return an empty CGRect if the bounds crossed the antimeridian. ([#12758](https://github.com/mapbox/mapbox-gl-native/pull/12758)) # 0.10.0 - August 15, 2018 diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj index 656121030c..7ee83bf483 100644 --- a/platform/macos/macos.xcodeproj/project.pbxproj +++ b/platform/macos/macos.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 0721493F1EE200E900085505 /* MGLImageSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 07A019EB1ED662D800ACD43E /* MGLImageSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 076171C5213A0DC200668A35 /* MGLMapViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 076171C4213A0DC200668A35 /* MGLMapViewTests.m */; }; 07A019EF1ED665CD00ACD43E /* MGLImageSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 07A019EC1ED662D800ACD43E /* MGLImageSource.mm */; }; 07A240941F675674002C8210 /* MGLComputedShapeSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 07A240921F67566F002C8210 /* MGLComputedShapeSourceTests.m */; }; 07BA4CAC1EE21887004528F5 /* MGLImageSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 07BA4CAB1EE21887004528F5 /* MGLImageSourceTests.m */; }; @@ -298,6 +299,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 076171C4213A0DC200668A35 /* MGLMapViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLMapViewTests.m; path = ../../darwin/test/MGLMapViewTests.m; sourceTree = ""; }; 07A019EB1ED662D800ACD43E /* MGLImageSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLImageSource.h; sourceTree = ""; }; 07A019EC1ED662D800ACD43E /* MGLImageSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLImageSource.mm; sourceTree = ""; }; 07A240921F67566F002C8210 /* MGLComputedShapeSourceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLComputedShapeSourceTests.m; sourceTree = ""; }; @@ -1108,6 +1110,7 @@ 1F95931A1E6DE2B600D5B294 /* MGLNSDateAdditionsTests.mm */, DA0CD58D1CF56F5800A5F5A5 /* MGLFeatureTests.mm */, DAE6C3C81CC34BD800DB3429 /* MGLGeometryTests.mm */, + 076171C4213A0DC200668A35 /* MGLMapViewTests.m */, DAE7DEC31E24549F007505A6 /* MGLNSStringAdditionsTests.m */, DAE6C3C91CC34BD800DB3429 /* MGLOfflinePackTests.m */, DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */, @@ -1610,6 +1613,7 @@ DAE6C3D21CC34C9900DB3429 /* MGLGeometryTests.mm in Sources */, DA87A9A41DCACC5000810D09 /* MGLSymbolStyleLayerTests.mm in Sources */, 40E1601D1DF217D6005EA6D9 /* MGLStyleLayerTests.m in Sources */, + 076171C5213A0DC200668A35 /* MGLMapViewTests.m in Sources */, 170A82BF201BDD1B00943087 /* MGLHeatmapStyleLayerTests.mm in Sources */, 1F95931B1E6DE2B600D5B294 /* MGLNSDateAdditionsTests.mm in Sources */, DAF25721201902C100367EF5 /* MGLHillshadeStyleLayerTests.mm in Sources */, diff --git a/platform/macos/src/MGLMapView.h b/platform/macos/src/MGLMapView.h index 305a1348e4..ddb5747109 100644 --- a/platform/macos/src/MGLMapView.h +++ b/platform/macos/src/MGLMapView.h @@ -1088,6 +1088,11 @@ MGL_EXPORT IB_DESIGNABLE /** Converts a geographic bounding box to a rectangle in the given view’s coordinate system. + + To bring both sides of the antimeridian or international date line into view, + specify some longitudes less than −180 degrees or greater than 180 degrees. For + example, to show both Tokyo and San Francisco simultaneously, you could set the + visible bounds to extend from (35.68476, −220.24257) to (37.78428, −122.41310). @param bounds The geographic bounding box to convert. @param view The view in whose coordinate system the returned rectangle should diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index 3c1fe18499..92ba89f72d 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -2820,17 +2820,33 @@ public: } - (NSRect)convertCoordinateBounds:(MGLCoordinateBounds)bounds toRectToView:(nullable NSView *)view { - if (!CLLocationCoordinate2DIsValid(bounds.sw) || !CLLocationCoordinate2DIsValid(bounds.ne)) { - return CGRectNull; - } return [self convertLatLngBounds:MGLLatLngBoundsFromCoordinateBounds(bounds) toRectToView:view]; } /// Converts a geographic bounding box to a rectangle in the view’s coordinate /// system. - (NSRect)convertLatLngBounds:(mbgl::LatLngBounds)bounds toRectToView:(nullable NSView *)view { - NSRect rect = { [self convertLatLng:bounds.southwest() toPointToView:view], NSZeroSize }; - rect = MGLExtendRect(rect, [self convertLatLng:bounds.northeast() toPointToView:view]); + auto northwest = bounds.northwest(); + auto northeast = bounds.northeast(); + auto southwest = bounds.southwest(); + auto southeast = bounds.southeast(); + + auto center = [self convertPoint:{ NSMidX(view.bounds), NSMidY(view.bounds) } toLatLngFromView:view]; + + // Extend bounds to account for the antimeridian + northwest.unwrapForShortestPath(center); + northeast.unwrapForShortestPath(center); + southwest.unwrapForShortestPath(center); + southeast.unwrapForShortestPath(center); + + auto correctedLatLngBounds = mbgl::LatLngBounds::empty(); + correctedLatLngBounds.extend(northwest); + correctedLatLngBounds.extend(northeast); + correctedLatLngBounds.extend(southwest); + correctedLatLngBounds.extend(southeast); + + NSRect rect = { [self convertLatLng:correctedLatLngBounds.southwest() toPointToView:view], CGSizeZero }; + rect = MGLExtendRect(rect, [self convertLatLng:correctedLatLngBounds.northeast() toPointToView:view]); return rect; } -- cgit v1.2.1