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

Cherry-pick master changes into release-boba (mid-February edition) #11249

Merged
merged 8 commits into from
Feb 20, 2018
21 changes: 18 additions & 3 deletions platform/darwin/test/MGLCoordinateFormatterTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ - (void)testStrings {
coordinate = CLLocationCoordinate2DMake(38.9131982, -77.0325453144239);
XCTAssertEqualObjects([shortFormatter stringFromCoordinate:coordinate], @"38°54′48″N, 77°1′57″W");
XCTAssertEqualObjects([mediumFormatter stringFromCoordinate:coordinate], @"38°54′48″ north, 77°1′57″ west");
XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees, 54 minutes, and 48 seconds north by 77 degrees, 1 minute, and 57 seconds west");
if (@available(iOS 9.0, *)) {
XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees, 54 minutes, and 48 seconds north by 77 degrees, 1 minute, and 57 seconds west");
} else {
// Foundation in iOS 8 does not know how to pluralize coordinates.
XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degree(s), 54 minute(s), and 48 second(s) north by 77 degree(s), 1 minute(s), and 57 second(s) west");
}

shortFormatter.allowsSeconds = NO;
mediumFormatter.allowsSeconds = NO;
Expand All @@ -33,7 +38,12 @@ - (void)testStrings {
coordinate = CLLocationCoordinate2DMake(38.9131982, -77.0325453144239);
XCTAssertEqualObjects([shortFormatter stringFromCoordinate:coordinate], @"38°55′N, 77°2′W");
XCTAssertEqualObjects([mediumFormatter stringFromCoordinate:coordinate], @"38°55′ north, 77°2′ west");
XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees and 55 minutes north by 77 degrees and 2 minutes west");
if (@available(iOS 9.0, *)) {
XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees and 55 minutes north by 77 degrees and 2 minutes west");
} else {
// Foundation in iOS 8 does not know how to pluralize coordinates.
XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degree(s) and 55 minute(s) north by 77 degree(s) and 2 minute(s) west");
}

shortFormatter.allowsMinutes = NO;
mediumFormatter.allowsMinutes = NO;
Expand All @@ -42,7 +52,12 @@ - (void)testStrings {
coordinate = CLLocationCoordinate2DMake(38.9131982, -77.0325453144239);
XCTAssertEqualObjects([shortFormatter stringFromCoordinate:coordinate], @"39°N, 77°W");
XCTAssertEqualObjects([mediumFormatter stringFromCoordinate:coordinate], @"39° north, 77° west");
XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"39 degrees north by 77 degrees west");
if (@available(iOS 9.0, *)) {
XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"39 degrees north by 77 degrees west");
} else {
// Foundation in iOS 8 does not know how to pluralize coordinates.
XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"39 degree(s) north by 77 degree(s) west");
}
}

@end
2 changes: 1 addition & 1 deletion platform/darwin/test/MGLDocumentationExampleTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
}
//#-end-example-code

wait(for: [expectation], timeout: 1)
wait(for: [expectation], timeout: 5)
}

// For testMGLMapView().
Expand Down
38 changes: 21 additions & 17 deletions platform/darwin/test/MGLExpressionTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -573,23 +573,27 @@ - (void)testInterpolationExpressionObject {
}

- (void)testConditionalExpressionObject {
{
NSPredicate *conditional = [NSPredicate predicateWithFormat:@"1 = 2"];
NSExpression *trueExpression = [NSExpression expressionForConstantValue:@YES];
NSExpression *falseExpression = [NSExpression expressionForConstantValue:@NO];
NSExpression *expression = [NSExpression expressionForConditional:conditional trueExpression:trueExpression falseExpression:falseExpression];
NSArray *jsonExpression = @[@"case", @[@"==", @1, @2], @YES, @NO];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([NSExpression expressionWithFormat:@"TERNARY(1 = 2, TRUE, FALSE)"].mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression);
}
{
NSExpression *expression = [NSExpression expressionWithFormat:@"TERNARY(0 = 1, TRUE, TERNARY(1 = 2, TRUE, FALSE))"];
NSArray *jsonExpression = @[@"case", @[@"==", @0, @1], @YES, @[@"==", @1, @2], @YES, @NO];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression);
// FIXME: This test crashes because iOS 8 doesn't have `+[NSExpression expressionForConditional:trueExpression:falseExpression:]`.
// https://github.com/mapbox/mapbox-gl-native/issues/11007
if (@available(iOS 9.0, *)) {
{
NSPredicate *conditional = [NSPredicate predicateWithFormat:@"1 = 2"];
NSExpression *trueExpression = [NSExpression expressionForConstantValue:@YES];
NSExpression *falseExpression = [NSExpression expressionForConstantValue:@NO];
NSExpression *expression = [NSExpression expressionForConditional:conditional trueExpression:trueExpression falseExpression:falseExpression];
NSArray *jsonExpression = @[@"case", @[@"==", @1, @2], @YES, @NO];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([NSExpression expressionWithFormat:@"TERNARY(1 = 2, TRUE, FALSE)"].mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression);
}
{
NSExpression *expression = [NSExpression expressionWithFormat:@"TERNARY(0 = 1, TRUE, TERNARY(1 = 2, TRUE, FALSE))"];
NSArray *jsonExpression = @[@"case", @[@"==", @0, @1], @YES, @[@"==", @1, @2], @YES, @NO];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression);
}
}
}

Expand Down
27 changes: 17 additions & 10 deletions platform/darwin/test/MGLFeatureTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -298,29 +298,36 @@ - (void)testPointCollectionFeatureGeoJSONDictionary {
}

- (void)testShapeCollectionFeatureGeoJSONDictionary {
MGLPointAnnotation *pointFeature = [[MGLPointAnnotation alloc] init];
MGLPointFeature *pointFeature = [[MGLPointFeature alloc] init];
CLLocationCoordinate2D pointCoordinate = { 10, 10 };
pointFeature.coordinate = pointCoordinate;

CLLocationCoordinate2D coord1 = { 0, 0 };
CLLocationCoordinate2D coord2 = { 10, 10 };
CLLocationCoordinate2D coords[] = { coord1, coord2 };
MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coords count:2];
MGLPolylineFeature *polylineFeature = [MGLPolylineFeature polylineWithCoordinates:coords count:2];

MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[pointFeature, polylineFeature]];

MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[pointFeature,
polyline]];
// A GeoJSON feature
NSDictionary *geoJSONFeature = [shapeCollectionFeature geoJSONDictionary];

// it has the correct geometry
NSDictionary *expectedGeometry = @{@"type": @"GeometryCollection",
@"geometries": @[
@{@"type": @"Point",
@"coordinates": @[@(pointCoordinate.longitude), @(pointCoordinate.latitude)]},
@{@"type": @"LineString",
@"coordinates": @[@[@(coord1.longitude), @(coord1.latitude)],
@[@(coord2.longitude), @(coord2.latitude)]]}
]};
@{ @"geometry": @{@"type": @"Point",
@"coordinates": @[@(pointCoordinate.longitude), @(pointCoordinate.latitude)]},
@"properties": [NSNull null],
@"type": @"Feature",
},
@{ @"geometry": @{@"type": @"LineString",
@"coordinates": @[@[@(coord1.longitude), @(coord1.latitude)],
@[@(coord2.longitude), @(coord2.latitude)]]},
@"properties": [NSNull null],
@"type": @"Feature",
}
]
};
XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry);

// When the shape collection is created with an empty array of shapes
Expand Down
4 changes: 4 additions & 0 deletions platform/ios/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Labels are now transliterated from more languages when VoiceOver is enabled. ([#10881](https://github.com/mapbox/mapbox-gl-native/pull/10881))
* Long-pressing the attribution button causes the SDK’s version number to be displayed in the action sheet that appears. ([#10650](https://github.com/mapbox/mapbox-gl-native/pull/10650))

## 3.7.5 - February 16, 2018

* Fixed an issue where requesting location services permission would trigger an unrecoverable loop. ([#11229](https://github.com/mapbox/mapbox-gl-native/pull/11229))

## 3.7.4 - February 12, 2018

* Added the `MGLTileSourceOptionTileCoordinateBounds` option to create an `MGLTileSource` that only supplies tiles within a specific geographic bounding box. ([#11141](https://github.com/mapbox/mapbox-gl-native/pull/11141))
Expand Down
3 changes: 2 additions & 1 deletion platform/ios/src/MGLMapView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -543,8 +543,9 @@ - (void)commonInit
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willTerminate) name:UIApplicationWillTerminateNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sleepGL:) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(wakeGL:) name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sleepGL:) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(wakeGL:) name:UIApplicationDidBecomeActiveNotification object:nil];
// As of 3.7.5, we intentionally do not listen for `UIApplicationWillResignActiveNotification` or call `sleepGL:` in response to it, as doing
// so causes a loop when asking for location permission. See: https://github.com/mapbox/mapbox-gl-native/issues/11225

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
Expand Down
2 changes: 1 addition & 1 deletion platform/ios/test/MGLMapViewLayoutTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ - (void)testOrnamentPlacement {
CGFloat bottomSafeAreaInset = 0.0;
double accuracy = 0.01;

if ( [self.mapView respondsToSelector:@selector(safeAreaInsets)] ) {
if (@available(iOS 11.0, *)) {
bottomSafeAreaInset = self.mapView.safeAreaInsets.bottom;
}

Expand Down
7 changes: 5 additions & 2 deletions src/mbgl/renderer/tile_pyramid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,13 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer
auto it = tiles.find(tileID);
return it == tiles.end() ? nullptr : it->second.get();
};


// The min and max zoom for TileRange are based on the updateRenderables algorithm.
// Tiles are created at the ideal tile zoom or at lower zoom levels. Child
// tiles are used from the cache, but not created.
optional<util::TileRange> tileRange = {};
if (bounds) {
tileRange = util::TileRange::fromLatLngBounds(*bounds, std::min(tileZoom, (int32_t)zoomRange.max));
tileRange = util::TileRange::fromLatLngBounds(*bounds, zoomRange.min, std::min(tileZoom, (int32_t)zoomRange.max));
}
auto createTileFn = [&](const OverscaledTileID& tileID) -> Tile* {
if (tileRange && !tileRange->contains(tileID.canonical)) {
Expand Down
60 changes: 40 additions & 20 deletions src/mbgl/util/tile_range.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,61 @@
#include <mbgl/util/projection.hpp>

namespace mbgl {

namespace util {

class TileRange {
public:
Range<Point<double>> range;
uint8_t z;
Range<Point<uint32_t>> range;
Range<uint8_t> zoomRange;

// Compute the range of tiles covered by the bounds at maxZoom.
static TileRange fromLatLngBounds(const LatLngBounds& bounds, uint8_t minZoom, uint8_t maxZoom) {
if (minZoom > maxZoom) {
std::swap(minZoom, maxZoom);
}

auto swProj = Projection::project(bounds.southwest().wrapped(), maxZoom);
auto ne = bounds.northeast();
auto neProj = Projection::project(ne.longitude() > util::LONGITUDE_MAX ? ne.wrapped() : ne , maxZoom);

const auto maxTile = std::pow(2.0, maxZoom);
const auto minX = static_cast<uint32_t>(std::floor(swProj.x));
const auto maxX = static_cast<uint32_t>(std::floor(neProj.x));
const auto minY = static_cast<uint32_t>(util::clamp(std::floor(neProj.y), 0.0 , maxTile));
const auto maxY = static_cast<uint32_t>(util::clamp(std::floor(swProj.y), 0.0, maxTile));

return TileRange({ {minX, minY}, {maxX, maxY} }, {minZoom, maxZoom});
}

// Compute the range of tiles covered by the bounds.
static TileRange fromLatLngBounds(const LatLngBounds& bounds, uint8_t z) {
auto swProj = Projection::project(bounds.southwest().wrapped(), z);
auto ne = bounds.northeast();
auto neProj = Projection::project(ne.longitude() > util::LONGITUDE_MAX ? ne.wrapped() : ne , z);
const auto minX = std::floor(swProj.x);
const auto maxX = std::ceil(neProj.x);
const auto minY = std::floor(neProj.y);
const auto maxY = std::ceil(swProj.y);
return TileRange({ {minX, minY}, {maxX, maxY} }, z);
return fromLatLngBounds(bounds, z, z);
}

bool contains(const CanonicalTileID& tileID) {
return z == tileID.z &&
(range.min.x >= range.max.x ? //For wrapped bounds
tileID.x >= range.min.x || tileID.x < range.max.x :
tileID.x < range.max.x && tileID.x >= range.min.x) &&
tileID.y < range.max.y &&
tileID.y >= range.min.y;
if (tileID.z <= zoomRange.max && tileID.z >= zoomRange.min) {
if (tileID.z == 0) {
return true;
}
uint8_t dz = (zoomRange.max - tileID.z);
auto x0 = range.min.x >> dz;
auto x1 = range.max.x >> dz;
auto y0 = range.min.y >> dz;
auto y1 = range.max.y >> dz;
return (range.min.x > range.max.x ? //For wrapped bounds
tileID.x >= x0 || tileID.x <= x1 :
tileID.x <= x1 && tileID.x >= x0) &&
tileID.y <= y1 &&
tileID.y >= y0;
}
return false;
}

private:
TileRange(Range<Point<double>> range_, uint8_t z_)
TileRange(Range<Point<uint32_t>> range_, Range<uint8_t> z_)
: range(range_),
z(z_) {
zoomRange(z_) {
}

};

} // namespace util
Expand Down
13 changes: 12 additions & 1 deletion test/util/tile_range.test.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

#include <mbgl/util/tile_range.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/map/transform.hpp>
Expand All @@ -25,6 +24,18 @@ TEST(TileRange, ContainsBoundsFromTile) {
EXPECT_TRUE(range.contains(CanonicalTileID(10, 162, 395)));
}
}

TEST(TileRange, ContainsMultiZoom) {
auto wrappedBounds = LatLngBounds::hull({ 37.6609, -122.5744 }, { 37.8271, -122.3204 });
auto range = util::TileRange::fromLatLngBounds(wrappedBounds, 5, 13);
EXPECT_FALSE(range.contains(CanonicalTileID(0, 0, 0)));
EXPECT_FALSE(range.contains(CanonicalTileID(5, 3, 11)));
EXPECT_FALSE(range.contains(CanonicalTileID(6, 9, 22)));
EXPECT_TRUE(range.contains(CanonicalTileID(5, 5, 12)));
EXPECT_TRUE(range.contains(CanonicalTileID(6, 10, 24)));
EXPECT_TRUE(range.contains(CanonicalTileID(13, 1310, 3166)));
}

TEST(TileRange, ContainsIntersectingTiles) {
auto bounds = LatLngBounds::hull({ 37.6609, -122.5744 }, { 37.8271, -122.3204 });
auto range = util::TileRange::fromLatLngBounds(bounds, 13);
Expand Down