Created
May 10, 2017 13:21
-
-
Save wattnpapa/ab6de0fc246d29ec2372ec954c4d966d to your computer and use it in GitHub Desktop.
MKMapViewZoomLevel.swift
This file contains 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
// | |
// MKMapViewZoomLevel.swift | |
// | |
// Created by Johannes Rudolph on 10.05.17. | |
// Based on http://troybrant.net/blog/2010/01/set-the-zoom-level-of-an-mkmapview/ | |
// | |
import Foundation | |
import MapKit | |
extension MKMapView { | |
func MERCATOR_RADIUS() -> Double { | |
return 85445659.44705395 | |
} | |
func MERCATOR_OFFSET() -> Double { | |
return 268435456.0 | |
} | |
func longitudeToPixelSpaceX(longitude: Double) -> Double { | |
return round(MERCATOR_OFFSET() + MERCATOR_RADIUS() * longitude * .pi / 180.0); | |
} | |
func latitudeToPixelSpaceY(latitude: Double) -> Double { | |
return round( Double(Float(MERCATOR_OFFSET()) - Float(MERCATOR_RADIUS()) * logf((1 + sinf(Float(latitude * .pi / 180.0))) / (1 - sinf(Float(latitude * .pi / 180.0)))) / Float(2.0))) | |
} | |
func pixelSpaceXToLongitude(pixelX: Double) -> Double { | |
return ((round(pixelX) - MERCATOR_OFFSET()) / MERCATOR_RADIUS()) * 180.0 / .pi; | |
} | |
func pixelSpaceYToLatitude(pixelY: Double) -> Double { | |
return (.pi / 2.0 - 2.0 * atan(exp((round(pixelY) - MERCATOR_OFFSET()) / MERCATOR_RADIUS()))) * 180.0 / .pi; | |
} | |
func coordinateSpanWithMapView(mapView: MKMapView, centerCoordinate: CLLocationCoordinate2D, zoomLevel: Int) -> MKCoordinateSpan { | |
// convert center coordiate to pixel space | |
let centerPixelX = self.longitudeToPixelSpaceX(longitude: centerCoordinate.longitude) | |
let centerPixelY = self.latitudeToPixelSpaceY(latitude: centerCoordinate.latitude) | |
// determine the scale value from the zoom level | |
let zoomExponent = Double(20 - zoomLevel) | |
let zoomScale = pow(2.0, zoomExponent) | |
// scale the map’s size in pixel space | |
let mapSizeInPixels = mapView.bounds.size | |
let scaledMapWidth = Double(mapSizeInPixels.width) * zoomScale | |
let scaledMapHeight = Double(mapSizeInPixels.height) * zoomScale; | |
// figure out the position of the top-left pixel | |
let topLeftPixelX = centerPixelX - (scaledMapWidth / 2); | |
let topLeftPixelY = centerPixelY - (scaledMapHeight / 2); | |
// find delta between left and right longitudes | |
let minLng = self.pixelSpaceXToLongitude(pixelX: topLeftPixelX) | |
let maxLng = self.pixelSpaceXToLongitude(pixelX: topLeftPixelX + scaledMapWidth) | |
let longitudeDelta = maxLng - minLng; | |
// find delta between top and bottom latitudes | |
let minLat = self.pixelSpaceYToLatitude(pixelY: topLeftPixelY) | |
let maxLat = self.pixelSpaceYToLatitude(pixelY: topLeftPixelY + scaledMapHeight) | |
let latitudeDelta = -1 * (maxLat - minLat) | |
// create and return the lat/lng span | |
return MKCoordinateSpanMake(latitudeDelta, longitudeDelta) | |
} | |
func zoomLevel() -> Double{ | |
let centerPixelSpaceX = self.longitudeToPixelSpaceX(longitude: self.centerCoordinate.longitude) | |
let lonLeft = self.centerCoordinate.longitude - (self.region.span.longitudeDelta / 2) | |
let leftPixelSpaceX = self.longitudeToPixelSpaceX(longitude: lonLeft) | |
let pixelSpaceWidth = abs(centerPixelSpaceX - leftPixelSpaceX) * 2 | |
let zoomScale = pixelSpaceWidth / Double(self.bounds.size.width) | |
let zoomExponent = self.logC(val: zoomScale, forBase: 2) | |
let zoomLevel = 20 - zoomExponent | |
return zoomLevel | |
} | |
func logC(val: Double, forBase base: Double) -> Double { | |
return log(val)/log(base) | |
} | |
func setCenterCoordinate(centerCoordinate: CLLocationCoordinate2D, zoomLevel: Int, animated: Bool){ | |
// clamp large numbers to 28 | |
let zoomL = min(zoomLevel, 28); | |
// use the zoom level to compute the region | |
let span = self.coordinateSpanWithMapView(mapView: self, centerCoordinate: centerCoordinate, zoomLevel: zoomL) | |
let region = MKCoordinateRegionMake(centerCoordinate, span) | |
// set the region like normal | |
self.setRegion(region, animated: animated) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment