summaryrefslogtreecommitdiff
path: root/platform/ios/test/MGLMapViewDirectionTests.mm
blob: d3990b581ba74e7270095db26a6f0617c888f5d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#import <Mapbox/Mapbox.h>
#import <XCTest/XCTest.h>

#import <mbgl/math/wrap.hpp>

static MGLMapView *mapView;

@interface MGLMapView (MGLMapViewDirectionTests)
- (void)handleRotateGesture:(UIRotationGestureRecognizer *)rotate;
- (void)resetNorthAnimated:(BOOL)animated;
@end

@interface UIRotationGestureRecognizer (MGLMapViewDirectionTests)
@property (nonatomic, readwrite) UIGestureRecognizerState state;
@end

@interface MGLMapViewDirectionTests : XCTestCase
@end

@implementation MGLMapViewDirectionTests

- (void)setUp {
    [super setUp];

    [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"];
    NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"];
    mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 64, 64) styleURL:styleURL];
}

- (void)tearDown {
    mapView = nil;
    [MGLAccountManager setAccessToken:nil];
    [super tearDown];
}

- (void)testDirection {
    mapView.zoomLevel = 0;
    mapView.direction = 30;
    XCTAssertEqual(mapView.direction, 0, @"Rotation is not allowed at world-scale zoom levels.");

    mapView.zoomLevel = 15;

    for (NSNumber *degrees in @[@-999, @-359, @-240, @-180, @-90, @-45, @0, @45, @90, @180, @240, @360, @999]) {
        double inputDegrees = [degrees doubleValue];
        double wrappedDegrees = mbgl::util::wrap(inputDegrees, 0., 360.);
        mapView.direction = inputDegrees;
        XCTAssertEqualWithAccuracy(mapView.direction, wrappedDegrees, 0.001);
    }

    [mapView resetNorthAnimated:NO];
    XCTAssertEqual(mapView.direction, 0, @"Reset-to-north should set direction to 0°.");
}

- (void)testRotateEnabled {
    mapView.zoomLevel = 10;

    UIRotationGestureRecognizer *gesture = [[UIRotationGestureRecognizer alloc] initWithTarget:nil action:nil];
    gesture.state = UIGestureRecognizerStateBegan;
    gesture.rotation = MGLRadiansFromDegrees(30);
    CGFloat wrappedRotation = mbgl::util::wrap(-MGLDegreesFromRadians(gesture.rotation), 0., 360.);

    // Disabled
    {
        mapView.rotateEnabled = NO;
        XCTAssertEqual(mapView.allowsRotating, NO);

        [mapView handleRotateGesture:gesture];
        XCTAssertNotEqual(mapView.direction, wrappedRotation, @"Gestural rotation should not work when rotation is disabled.");

        mapView.direction = 45.f;
        XCTAssertEqualWithAccuracy(mapView.direction, 45, 0.001, @"Programmatic rotation is allowed when rotateEnabled = NO.");
    }

    // Enabled
    {
        [mapView resetNorthAnimated:NO];
        mapView.rotateEnabled = YES;
        XCTAssertEqual(mapView.allowsRotating, YES);

        gesture.state = UIGestureRecognizerStateChanged;
        gesture.rotation = MGLRadiansFromDegrees(30);
        [mapView handleRotateGesture:gesture];
        XCTAssertEqualWithAccuracy(mapView.direction, wrappedRotation, 0.001, @"Gestural rotation should work when rotation is enabled.");
    }
}

- (void)testRotateGesture {
    mapView.zoomLevel = 15;

    UIRotationGestureRecognizer *gesture = [[UIRotationGestureRecognizer alloc] initWithTarget:nil action:nil];
    gesture.state = UIGestureRecognizerStateBegan;
    gesture.rotation = 0;
    [mapView handleRotateGesture:gesture];
    XCTAssertEqual(mapView.direction, gesture.rotation);

    for (NSNumber *degrees in @[@-999, @-360, @-240, @-180, @-90, @-45, @0, @45, @90, @180, @240, @359, @999]) {
        gesture.state = UIGestureRecognizerStateChanged;
        gesture.rotation = MGLRadiansFromDegrees([degrees doubleValue]);
        [mapView handleRotateGesture:gesture];
        CGFloat wrappedRotation = mbgl::util::wrap(-MGLDegreesFromRadians(gesture.rotation), 0., 360.);
        XCTAssertEqualWithAccuracy(mapView.direction, wrappedRotation, 0.001, @"Map direction should match gesture rotation for input of %@°.", degrees);
    }
}

- (void)testCompassRotation {
    mapView.zoomLevel = 15;

    for (NSNumber *degrees in @[@-999, @-359, @-240, @-180, @-90, @-45, @0, @45, @90, @180, @240, @360, @999]) {
        mapView.direction = [degrees doubleValue];
        CGFloat wrappedDirection = mbgl::util::wrap(-mapView.direction, 0., 360.);
        CGAffineTransform rotation = CGAffineTransformMakeRotation(MGLRadiansFromDegrees(wrappedDirection));
        XCTAssertTrue(CGAffineTransformEqualToTransform(mapView.compassView.transform, rotation),
                      @"Compass transform direction %f° should equal wrapped transform direction %f° (~%.f°).", [self degreesFromAffineTransform:mapView.compassView.transform], [self degreesFromAffineTransform:rotation], wrappedDirection);
    }
}

- (void)testResetPosition {
    [mapView resetPosition];
    MGLMapCamera *defaultCamera = [MGLMapCamera cameraLookingAtCenterCoordinate:CLLocationCoordinate2DMake(0, 0) altitude:mapView.camera.altitude pitch:0 heading:0];
    XCTAssertTrue([mapView.camera isEqualToMapCamera:defaultCamera], @"Map camera %@ should be equal to default camera %@.", mapView.camera, defaultCamera);
}

- (CGFloat)degreesFromAffineTransform:(CGAffineTransform)transform {
    CGFloat angle = atan2f(transform.b, transform.a);
    return MGLDegreesFromRadians(angle);
}

@end