Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

merged code from Adam Cohen-Rose

  • Loading branch information...
commit 8a691f386d1d5dd31d7dc25489a4be604933982c 1 parent d0c55c1
@johndpope authored
Showing with 86 additions and 19 deletions.
  1. +4 −0 MKMapView+ZoomLevel.h
  2. +82 −19 MKMapView+ZoomLevel.m
View
4 MKMapView+ZoomLevel.h
@@ -6,6 +6,10 @@
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
zoomLevel:(NSUInteger)zoomLevel
animated:(BOOL)animated;
+
+-(MKCoordinateRegion)coordinateRegionWithMapView:(MKMapView *)mapView
+ centerCoordinate:(CLLocationCoordinate2D)centerCoordinate
+ andZoomLevel:(NSUInteger)zoomLevel;
- (NSUInteger) zoomLevel;
@end
View
101 MKMapView+ZoomLevel.m
@@ -1,4 +1,3 @@
-// MKMapView+ZoomLevel.m
#import "MKMapView+ZoomLevel.h"
#define MERCATOR_OFFSET 268435456
@@ -9,22 +8,28 @@ @implementation MKMapView (ZoomLevel)
#pragma mark -
#pragma mark Map conversion methods
-- (double)longitudeToPixelSpaceX:(double)longitude
++ (double)longitudeToPixelSpaceX:(double)longitude
{
return round(MERCATOR_OFFSET + MERCATOR_RADIUS * longitude * M_PI / 180.0);
}
-- (double)latitudeToPixelSpaceY:(double)latitude
++ (double)latitudeToPixelSpaceY:(double)latitude
{
- return round(MERCATOR_OFFSET - MERCATOR_RADIUS * logf((1 + sinf(latitude * M_PI / 180.0)) / (1 - sinf(latitude * M_PI / 180.0))) / 2.0);
+ if (latitude == 90.0) {
+ return 0;
+ } else if (latitude == -90.0) {
+ return MERCATOR_OFFSET * 2;
+ } else {
+ return round(MERCATOR_OFFSET - MERCATOR_RADIUS * logf((1 + sinf(latitude * M_PI / 180.0)) / (1 - sinf(latitude * M_PI / 180.0))) / 2.0);
+ }
}
-- (double)pixelSpaceXToLongitude:(double)pixelX
++ (double)pixelSpaceXToLongitude:(double)pixelX
{
return ((round(pixelX) - MERCATOR_OFFSET) / MERCATOR_RADIUS) * 180.0 / M_PI;
}
-- (double)pixelSpaceYToLatitude:(double)pixelY
++ (double)pixelSpaceYToLatitude:(double)pixelY
{
return (M_PI / 2.0 - 2.0 * atan(exp((round(pixelY) - MERCATOR_OFFSET) / MERCATOR_RADIUS))) * 180.0 / M_PI;
}
@@ -33,12 +38,12 @@ - (double)pixelSpaceYToLatitude:(double)pixelY
#pragma mark Helper methods
- (MKCoordinateSpan)coordinateSpanWithMapView:(MKMapView *)mapView
- centerCoordinate:(CLLocationCoordinate2D)centerCoordinate
- andZoomLevel:(NSUInteger)zoomLevel
+ centerCoordinate:(CLLocationCoordinate2D)centerCoordinate
+ andZoomLevel:(NSUInteger)zoomLevel
{
// convert center coordiate to pixel space
- double centerPixelX = [self longitudeToPixelSpaceX:centerCoordinate.longitude];
- double centerPixelY = [self latitudeToPixelSpaceY:centerCoordinate.latitude];
+ double centerPixelX = [MKMapView longitudeToPixelSpaceX:centerCoordinate.longitude];
+ double centerPixelY = [MKMapView latitudeToPixelSpaceY:centerCoordinate.latitude];
// determine the scale value from the zoom level
NSInteger zoomExponent = 20 - zoomLevel;
@@ -54,13 +59,13 @@ - (MKCoordinateSpan)coordinateSpanWithMapView:(MKMapView *)mapView
double topLeftPixelY = centerPixelY - (scaledMapHeight / 2);
// find delta between left and right longitudes
- CLLocationDegrees minLng = [self pixelSpaceXToLongitude:topLeftPixelX];
- CLLocationDegrees maxLng = [self pixelSpaceXToLongitude:topLeftPixelX + scaledMapWidth];
+ CLLocationDegrees minLng = [MKMapView pixelSpaceXToLongitude:topLeftPixelX];
+ CLLocationDegrees maxLng = [MKMapView pixelSpaceXToLongitude:topLeftPixelX + scaledMapWidth];
CLLocationDegrees longitudeDelta = maxLng - minLng;
// find delta between top and bottom latitudes
- CLLocationDegrees minLat = [self pixelSpaceYToLatitude:topLeftPixelY];
- CLLocationDegrees maxLat = [self pixelSpaceYToLatitude:topLeftPixelY + scaledMapHeight];
+ CLLocationDegrees minLat = [MKMapView pixelSpaceYToLatitude:topLeftPixelY];
+ CLLocationDegrees maxLat = [MKMapView pixelSpaceYToLatitude:topLeftPixelY + scaledMapHeight];
CLLocationDegrees latitudeDelta = -1 * (maxLat - minLat);
// create and return the lat/lng span
@@ -72,8 +77,8 @@ - (MKCoordinateSpan)coordinateSpanWithMapView:(MKMapView *)mapView
#pragma mark Public methods
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
- zoomLevel:(NSUInteger)zoomLevel
- animated:(BOOL)animated
+ zoomLevel:(NSUInteger)zoomLevel
+ animated:(BOOL)animated
{
// clamp large numbers to 28
zoomLevel = MIN(zoomLevel, 28);
@@ -86,12 +91,69 @@ - (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
[self setRegion:region animated:animated];
}
+//KMapView cannot display tiles that cross the pole (as these would involve wrapping the map from top to bottom, something that a Mercator projection just cannot do).
+-(MKCoordinateRegion)coordinateRegionWithMapView:(MKMapView *)mapView
+ centerCoordinate:(CLLocationCoordinate2D)centerCoordinate
+ andZoomLevel:(NSUInteger)zoomLevel
+{
+ // clamp lat/long values to appropriate ranges
+ centerCoordinate.latitude = MIN(MAX(-90.0, centerCoordinate.latitude), 90.0);
+ centerCoordinate.longitude = fmod(centerCoordinate.longitude, 180.0);
+
+ // convert center coordiate to pixel space
+ double centerPixelX = [MKMapView longitudeToPixelSpaceX:centerCoordinate.longitude];
+ double centerPixelY = [MKMapView 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 left pixel
+ double topLeftPixelX = centerPixelX - (scaledMapWidth / 2);
+
+ // find delta between left and right longitudes
+ CLLocationDegrees minLng = [MKMapView pixelSpaceXToLongitude:topLeftPixelX];
+ CLLocationDegrees maxLng = [MKMapView pixelSpaceXToLongitude:topLeftPixelX + scaledMapWidth];
+ CLLocationDegrees longitudeDelta = maxLng - minLng;
+
+ // if we’re at a pole then calculate the distance from the pole towards the equator
+ // as MKMapView doesn’t like drawing boxes over the poles
+ double topPixelY = centerPixelY - (scaledMapHeight / 2);
+ double bottomPixelY = centerPixelY + (scaledMapHeight / 2);
+ BOOL adjustedCenterPoint = NO;
+ if (topPixelY > MERCATOR_OFFSET * 2) {
+ topPixelY = centerPixelY - scaledMapHeight;
+ bottomPixelY = MERCATOR_OFFSET * 2;
+ adjustedCenterPoint = YES;
+ }
+
+ // find delta between top and bottom latitudes
+ CLLocationDegrees minLat = [MKMapView pixelSpaceYToLatitude:topPixelY];
+ CLLocationDegrees maxLat = [MKMapView pixelSpaceYToLatitude:bottomPixelY];
+ CLLocationDegrees latitudeDelta = -1 * (maxLat - minLat);
+
+ // create and return the lat/lng span
+ MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
+ MKCoordinateRegion region = MKCoordinateRegionMake(centerCoordinate, span);
+ // once again, MKMapView doesn’t like drawing boxes over the poles
+ // so adjust the center coordinate to the center of the resulting region
+ if (adjustedCenterPoint) {
+ region.center.latitude = [MKMapView pixelSpaceYToLatitude:((bottomPixelY + topPixelY) / 2.0)];
+ }
+
+ return region;
+}
- (NSUInteger) zoomLevel {
MKCoordinateRegion region = self.region;
- double centerPixelX = [self longitudeToPixelSpaceX: region.center.longitude];
- double topLeftPixelX = [self longitudeToPixelSpaceX: region.center.longitude - region.span.longitudeDelta / 2];
+ double centerPixelX = [MKMapView longitudeToPixelSpaceX: region.center.longitude];
+ double topLeftPixelX = [MKMapView longitudeToPixelSpaceX: region.center.longitude - region.span.longitudeDelta / 2];
double scaledMapWidth = (centerPixelX - topLeftPixelX) * 2;
CGSize mapSizeInPixels = self.bounds.size;
@@ -102,4 +164,5 @@ - (NSUInteger) zoomLevel {
return zoomLevel;
}
-@end
+
+@end

0 comments on commit 8a691f3

Please sign in to comment.
Something went wrong with that request. Please try again.