Test fit to bounds; added MGLCoordinateBounds functions
Added a bunch of functions to work with MGLCoordinateBounds in a separate header analogous to MKGeometry.h. Added resolution-independent tests for common fit to bounds scenarios.
This commit is contained in:
@@ -36,6 +36,8 @@
|
||||
'../platform/ios/MGLUserLocationAnnotationView.m',
|
||||
'../include/mbgl/ios/MGLTypes.h',
|
||||
'../platform/ios/MGLTypes.m',
|
||||
'../include/mbgl/ios/MGLGeometry.h',
|
||||
'../platform/ios/MGLGeometry.m',
|
||||
'../include/mbgl/ios/MGLMultiPoint.h',
|
||||
'../platform/ios/MGLMultiPoint_Private.h',
|
||||
'../platform/ios/MGLMultiPoint.mm',
|
||||
|
||||
85
include/mbgl/ios/MGLGeometry.h
Normal file
85
include/mbgl/ios/MGLGeometry.h
Normal file
@@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
|
||||
#import "MGLTypes.h"
|
||||
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** Defines the area spanned by an MGLCoordinateBounds. */
|
||||
typedef struct {
|
||||
CLLocationDegrees latitudeDelta;
|
||||
CLLocationDegrees longitudeDelta;
|
||||
} MGLCoordinateSpan;
|
||||
|
||||
/** Creates a new MGLCoordinateSpan from the given latitudinal and longitudinal deltas. */
|
||||
NS_INLINE MGLCoordinateSpan MGLCoordinateSpanMake(CLLocationDegrees latitudeDelta, CLLocationDegrees longitudeDelta) {
|
||||
MGLCoordinateSpan span;
|
||||
span.latitudeDelta = latitudeDelta;
|
||||
span.longitudeDelta = longitudeDelta;
|
||||
return span;
|
||||
}
|
||||
|
||||
/** Returns `YES` if the two coordinate spans represent the same latitudinal change and the same longitudinal change. */
|
||||
NS_INLINE BOOL MGLCoordinateSpanEqualToCoordinateSpan(MGLCoordinateSpan span1, MGLCoordinateSpan span2) {
|
||||
return (span1.latitudeDelta == span2.latitudeDelta &&
|
||||
span1.longitudeDelta == span2.longitudeDelta);
|
||||
}
|
||||
|
||||
/** An area of zero width and zero height. */
|
||||
extern const MGLCoordinateSpan MGLCoordinateSpanZero;
|
||||
|
||||
/** A rectangular area as measured on a two-dimensional map projection. */
|
||||
typedef struct {
|
||||
CLLocationCoordinate2D sw;
|
||||
CLLocationCoordinate2D ne;
|
||||
} MGLCoordinateBounds;
|
||||
|
||||
/** Creates a new MGLCoordinateBounds structure from the given southwest and northeast coordinates. */
|
||||
NS_INLINE MGLCoordinateBounds MGLCoordinateBoundsMake(CLLocationCoordinate2D sw, CLLocationCoordinate2D ne) {
|
||||
MGLCoordinateBounds bounds;
|
||||
bounds.sw = sw;
|
||||
bounds.ne = ne;
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/** Returns `YES` if the two coordinate bounds are equal to each other. */
|
||||
NS_INLINE BOOL MGLCoordinateBoundsEqualToCoordinateBounds(MGLCoordinateBounds bounds1, MGLCoordinateBounds bounds2) {
|
||||
return (bounds1.sw.latitude == bounds2.sw.latitude &&
|
||||
bounds1.sw.longitude == bounds2.sw.longitude &&
|
||||
bounds1.ne.latitude == bounds2.ne.latitude &&
|
||||
bounds1.ne.longitude == bounds2.ne.longitude);
|
||||
}
|
||||
|
||||
/** Returns the area spanned by the coordinate bounds. */
|
||||
NS_INLINE MGLCoordinateSpan MGLCoordinateBoundsGetCoordinateSpan(MGLCoordinateBounds bounds) {
|
||||
return MGLCoordinateSpanMake(bounds.ne.latitude - bounds.sw.latitude,
|
||||
bounds.ne.longitude - bounds.sw.longitude);
|
||||
}
|
||||
|
||||
/** Returns a coordinate bounds with southwest and northeast coordinates that are offset from those of the source bounds. */
|
||||
NS_INLINE MGLCoordinateBounds MGLCoordinateBoundsOffset(MGLCoordinateBounds bounds, MGLCoordinateSpan offset) {
|
||||
MGLCoordinateBounds offsetBounds = bounds;
|
||||
offsetBounds.sw.latitude += offset.latitudeDelta;
|
||||
offsetBounds.sw.longitude += offset.longitudeDelta;
|
||||
offsetBounds.ne.latitude += offset.latitudeDelta;
|
||||
offsetBounds.ne.longitude += offset.longitudeDelta;
|
||||
return offsetBounds;
|
||||
}
|
||||
|
||||
/** Returns `YES` if the coordinate bounds covers no area.
|
||||
*
|
||||
* Note that a bounds may be empty but have a non-zero coordinate span (e.g., when its northeast point lies due north of its southwest point). */
|
||||
NS_INLINE BOOL MGLCoordinateBoundsIsEmpty(MGLCoordinateBounds bounds) {
|
||||
MGLCoordinateSpan span = MGLCoordinateBoundsGetCoordinateSpan(bounds);
|
||||
return span.latitudeDelta == 0 || span.longitudeDelta == 0;
|
||||
}
|
||||
|
||||
/** Returns a formatted string for the given coordinate bounds. */
|
||||
NS_INLINE NSString *MGLStringFromCoordinateBounds(MGLCoordinateBounds bounds) {
|
||||
return [NSString stringWithFormat:@"{{%.1f, %.1f}, {%.1f, %.1f}}",
|
||||
bounds.sw.latitude, bounds.sw.longitude,
|
||||
bounds.ne.latitude, bounds.ne.longitude];
|
||||
}
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,4 +1,4 @@
|
||||
#import "MGLTypes.h"
|
||||
#import "MGLGeometry.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
|
||||
#import "MGLAnnotation.h"
|
||||
#import "MGLTypes.h"
|
||||
#import "MGLGeometry.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !__has_feature(nullability)
|
||||
#define NS_ASSUME_NONNULL_BEGIN
|
||||
@@ -23,18 +24,6 @@ typedef NS_ENUM(NSUInteger, MGLUserTrackingMode) {
|
||||
MGLUserTrackingModeFollowWithHeading
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
CLLocationCoordinate2D sw;
|
||||
CLLocationCoordinate2D ne;
|
||||
} MGLCoordinateBounds;
|
||||
|
||||
NS_INLINE MGLCoordinateBounds MGLCoordinateBoundsMake(CLLocationCoordinate2D sw, CLLocationCoordinate2D ne) {
|
||||
MGLCoordinateBounds bounds;
|
||||
bounds.sw = sw;
|
||||
bounds.ne = ne;
|
||||
return bounds;
|
||||
}
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#pragma clang diagnostic push
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#import "MGLAccountManager.h"
|
||||
#import "MGLAnnotation.h"
|
||||
#import "MGLGeometry.h"
|
||||
#import "MGLMapView.h"
|
||||
#import "MGLMultiPoint.h"
|
||||
#import "MGLOverlay.h"
|
||||
|
||||
3
platform/ios/MGLGeometry.m
Normal file
3
platform/ios/MGLGeometry.m
Normal file
@@ -0,0 +1,3 @@
|
||||
#import "MGLGeometry.h"
|
||||
|
||||
const MGLCoordinateSpan MGLCoordinateSpanZero = {0, 0};
|
||||
@@ -1,5 +1,5 @@
|
||||
#import "MGLMultiPoint.h"
|
||||
#import "MGLTypes.h"
|
||||
#import "MGLGeometry.h"
|
||||
|
||||
#import <mbgl/util/geo.hpp>
|
||||
|
||||
|
||||
@@ -150,6 +150,41 @@
|
||||
@"disabling zoom gesture should disallow pinching");
|
||||
}
|
||||
|
||||
- (void)testFitToBounds {
|
||||
// No-op
|
||||
MGLCoordinateBounds initialBounds = tester.mapView.visibleCoordinateBounds;
|
||||
[tester.mapView setVisibleCoordinateBounds:initialBounds animated:NO];
|
||||
XCTAssertEqualObjects(MGLStringFromCoordinateBounds(initialBounds),
|
||||
MGLStringFromCoordinateBounds(tester.mapView.visibleCoordinateBounds),
|
||||
@"setting visible coordinate bounds to currently visible coordinate bounds should be a no-op");
|
||||
|
||||
// Roundtrip after zooming
|
||||
tester.mapView.zoomLevel -= 3;
|
||||
[tester.mapView setVisibleCoordinateBounds:initialBounds animated:NO];
|
||||
XCTAssertEqualObjects(MGLStringFromCoordinateBounds(initialBounds),
|
||||
MGLStringFromCoordinateBounds(tester.mapView.visibleCoordinateBounds),
|
||||
@"after zooming out, setting visible coordinate bounds back to %@ should not leave them at %@",
|
||||
MGLStringFromCoordinateBounds(initialBounds),
|
||||
MGLStringFromCoordinateBounds(tester.mapView.visibleCoordinateBounds));
|
||||
tester.mapView.zoomLevel += 3;
|
||||
[tester.mapView setVisibleCoordinateBounds:initialBounds animated:NO];
|
||||
XCTAssertEqualObjects(MGLStringFromCoordinateBounds(initialBounds),
|
||||
MGLStringFromCoordinateBounds(tester.mapView.visibleCoordinateBounds),
|
||||
@"after zooming in, setting visible coordinate bounds back to %@ should not leave them at %@",
|
||||
MGLStringFromCoordinateBounds(initialBounds),
|
||||
MGLStringFromCoordinateBounds(tester.mapView.visibleCoordinateBounds));
|
||||
|
||||
// Roundtrip after panning
|
||||
MGLCoordinateBounds offsetBounds = MGLCoordinateBoundsOffset(initialBounds, MGLCoordinateSpanMake(0, 30));
|
||||
[tester.mapView setVisibleCoordinateBounds:offsetBounds animated:NO];
|
||||
[tester.mapView setVisibleCoordinateBounds:initialBounds animated:NO];
|
||||
XCTAssertEqualObjects(MGLStringFromCoordinateBounds(initialBounds),
|
||||
MGLStringFromCoordinateBounds(tester.mapView.visibleCoordinateBounds),
|
||||
@"after panning 30° to the east, setting visible coordinate bounds back to %@ should not leave them at %@",
|
||||
MGLStringFromCoordinateBounds(initialBounds),
|
||||
MGLStringFromCoordinateBounds(tester.mapView.visibleCoordinateBounds));
|
||||
}
|
||||
|
||||
- (void)testPan {
|
||||
CLLocationCoordinate2D centerCoordinate = tester.mapView.centerCoordinate;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user