Created
January 10, 2014 15:04
-
-
Save appsandwich/8355891 to your computer and use it in GitHub Desktop.
Get & set the zoom level of a MKMapView
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@interface MKMapView (Extensions) | |
-(double)as_zoomLevel; | |
-(void)as_setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(NSUInteger)zoomLevel animated:(BOOL)animated; | |
@end | |
static double mercadorRadius = 85445659.44705395; | |
static double mercadorOffset = 268435456; | |
@implementation MKMapView (Extensions) | |
-(double)as_zoomLevel { | |
// Derived from http://stackoverflow.com/questions/7594827/how-to-find-current-zoom-level-of-mkmapview | |
static double maxGoogleLevels = -1.0; | |
if (maxGoogleLevels < 0.0) | |
maxGoogleLevels = log2(MKMapSizeWorld.width / 256.0); | |
CLLocationDegrees longitudeDelta = self.region.span.longitudeDelta; | |
CGFloat mapWidthInPixels = self.bounds.size.width; | |
double zoomScale = longitudeDelta * mercadorRadius * M_PI / (180.0 * mapWidthInPixels); | |
double zoomer = maxGoogleLevels - log2( zoomScale ); | |
if ( zoomer < 0 ) zoomer = 0; | |
return zoomer; | |
} | |
// http://troybrant.net/blog/2010/01/set-the-zoom-level-of-an-mkmapview/ | |
#pragma mark - | |
#pragma mark Map conversion methods | |
-(double)as_longitudeToPixelSpaceX:(double)longitude { | |
return round(mercadorOffset + mercadorRadius * longitude * M_PI / 180.0); | |
} | |
-(double)as_latitudeToPixelSpaceY:(double)latitude { | |
return round(mercadorOffset - mercadorRadius * logf((1 + sinf(latitude * M_PI / 180.0)) / (1 - sinf(latitude * M_PI / 180.0))) / 2.0); | |
} | |
-(double)as_pixelSpaceXToLongitude:(double)pixelX { | |
return ((round(pixelX) - mercadorOffset) / mercadorRadius) * 180.0 / M_PI; | |
} | |
-(double)as_pixelSpaceYToLatitude:(double)pixelY { | |
return (M_PI / 2.0 - 2.0 * atan(exp((round(pixelY) - mercadorOffset) / mercadorRadius))) * 180.0 / M_PI; | |
} | |
#pragma mark - | |
#pragma mark Helper methods | |
-(MKCoordinateSpan)as_coordinateSpanWithMapView:(MKMapView *)mapView centerCoordinate:(CLLocationCoordinate2D)centerCoordinate andZoomLevel:(NSUInteger)zoomLevel { | |
// convert center coordiate to pixel space | |
double centerPixelX = [self as_longitudeToPixelSpaceX:centerCoordinate.longitude]; | |
double centerPixelY = [self as_latitudeToPixelSpaceY:centerCoordinate.latitude]; | |
// determine the scale value from the zoom level | |
NSInteger zoomExponent = 20 - zoomLevel; | |
double zoomScale = pow(2, zoomExponent); | |
// scale the map’s size in pixel space | |
CGSize mapSizeInPixels = mapView.bounds.size; | |
double scaledMapWidth = mapSizeInPixels.width * zoomScale; | |
double scaledMapHeight = mapSizeInPixels.height * zoomScale; | |
// figure out the position of the top-left pixel | |
double topLeftPixelX = centerPixelX - (scaledMapWidth / 2); | |
double topLeftPixelY = centerPixelY - (scaledMapHeight / 2); | |
// find delta between left and right longitudes | |
CLLocationDegrees minLng = [self as_pixelSpaceXToLongitude:topLeftPixelX]; | |
CLLocationDegrees maxLng = [self as_pixelSpaceXToLongitude:topLeftPixelX + scaledMapWidth]; | |
CLLocationDegrees longitudeDelta = maxLng - minLng; | |
// find delta between top and bottom latitudes | |
CLLocationDegrees minLat = [self as_pixelSpaceYToLatitude:topLeftPixelY]; | |
CLLocationDegrees maxLat = [self as_pixelSpaceYToLatitude:topLeftPixelY + scaledMapHeight]; | |
CLLocationDegrees latitudeDelta = -1 * (maxLat - minLat); | |
// create and return the lat/lng span | |
MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta); | |
return span; | |
} | |
-(void)as_setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(NSUInteger)zoomLevel animated:(BOOL)animated { | |
// clamp large numbers to 28 | |
zoomLevel = MIN(zoomLevel, 28); | |
// use the zoom level to compute the region | |
MKCoordinateSpan span = [self as_coordinateSpanWithMapView:self centerCoordinate:centerCoordinate andZoomLevel:zoomLevel]; | |
MKCoordinateRegion region = MKCoordinateRegionMake(centerCoordinate, span); | |
// set the region like normal | |
[self setRegion:region animated:animated];} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment