#import "MGLMapCamera.h" #include @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