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
|
#import "MGLMapCamera.h"
#include <mbgl/util/projection.hpp>
@implementation MGLMapCamera
+ (BOOL)supportsSecureCoding
{
return YES;
}
+ (instancetype)camera
{
return [[self alloc] init];
}
+ (instancetype)cameraLookingAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
fromEyeCoordinate:(CLLocationCoordinate2D)eyeCoordinate
eyeAltitude:(CLLocationDistance)eyeAltitude
{
mbgl::LatLng centerLatLng = mbgl::LatLng(centerCoordinate.latitude, centerCoordinate.longitude);
mbgl::LatLng eyeLatLng = mbgl::LatLng(eyeCoordinate.latitude, eyeCoordinate.longitude);
mbgl::ProjectedMeters centerMeters = mbgl::Projection::projectedMetersForLatLng(centerLatLng);
mbgl::ProjectedMeters eyeMeters = mbgl::Projection::projectedMetersForLatLng(eyeLatLng);
CLLocationDirection heading = std::atan((centerMeters.northing - eyeMeters.northing) /
(centerMeters.easting - eyeMeters.easting));
double groundDistance = std::hypot(centerMeters.northing - eyeMeters.northing,
centerMeters.easting - eyeMeters.easting);
CGFloat pitch = std::atan(eyeAltitude / groundDistance);
return [[self alloc] initWithCenterCoordinate:centerCoordinate
altitude:eyeAltitude
pitch:pitch
heading:heading];
}
+ (instancetype)cameraLookingAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
fromDistance:(CLLocationDistance)distance
pitch:(CGFloat)pitch
heading:(CLLocationDirection)heading
{
return [[self alloc] initWithCenterCoordinate:centerCoordinate
altitude:distance
pitch:pitch
heading:heading];
}
- (instancetype)initWithCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
altitude:(CLLocationDistance)altitude
pitch:(CGFloat)pitch
heading:(CLLocationDirection)heading
{
if (self = [super init])
{
_centerCoordinate = centerCoordinate;
_altitude = altitude;
_pitch = pitch;
_heading = heading;
}
return self;
}
- (nullable instancetype)initWithCoder:(NSCoder *)coder
{
if (self = [super init])
{
_centerCoordinate = CLLocationCoordinate2DMake([coder decodeDoubleForKey:@"centerLatitude"],
[coder decodeDoubleForKey:@"centerLongitude"]);
_altitude = [coder decodeDoubleForKey:@"altitude"];
_pitch = [coder decodeDoubleForKey:@"pitch"];
_heading = [coder decodeDoubleForKey:@"heading"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeDouble:_centerCoordinate.latitude forKey:@"centerLatitude"];
[coder encodeDouble:_centerCoordinate.longitude forKey:@"centerLongitude"];
[coder encodeDouble:_altitude forKey:@"altitude"];
[coder encodeDouble:_pitch forKey:@"pitch"];
[coder encodeDouble:_heading forKey:@"heading"];
}
- (id)copyWithZone:(nullable NSZone *)zone
{
return [[[self class] allocWithZone:zone] initWithCenterCoordinate:_centerCoordinate
altitude:_altitude
pitch:_pitch
heading:_heading];
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; centerCoordinate = %f, %f; altitude = %.0fm; heading = %.0f°; pitch = %.0f°>",
NSStringFromClass([self class]), (void *)self, _centerCoordinate.latitude, _centerCoordinate.longitude, _altitude, _heading, _pitch];
}
- (BOOL)isEqual:(id)other
{
if ( ! [other isKindOfClass:[self class]])
{
return NO;
}
if (other == self)
{
return YES;
}
MGLMapCamera *otherCamera = other;
return (_centerCoordinate.latitude == otherCamera.centerCoordinate.latitude
&& _centerCoordinate.longitude == otherCamera.centerCoordinate.longitude
&& _altitude == otherCamera.altitude
&& _pitch == otherCamera.pitch && _heading == otherCamera.heading);
}
- (NSUInteger)hash
{
return (@(_centerCoordinate.latitude).hash + @(_centerCoordinate.longitude).hash
+ @(_altitude).hash + @(_pitch).hash + @(_heading).hash);
}
@end
|