Created
June 23, 2017 20:16
-
-
Save dgyesbreghs/800cb2f98f4d258c7a6e021997642f52 to your computer and use it in GitHub Desktop.
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
// | |
// MKMapView+ZoomLevel.swift | |
// Monizze | |
// | |
// Created by Dylan Gyesbreghs on 23/06/2017. | |
// Copyright © 2017 DGyesbreghs. All rights reserved. | |
// https://oleb.net/blog/2010/05/set-the-zoom-level-of-mkmapview/ | |
// | |
import MapKit | |
extension MKMapView { | |
open var currentZoomLevel: Int { | |
let maxZoom: Double = 24 | |
let zoomScale = visibleMapRect.size.width / Double(frame.size.width) | |
let zoomExponent = log2(zoomScale) | |
return Int(maxZoom - ceil(zoomExponent)) | |
} | |
open func setCenterCoordinate(_ centerCoordinate: CLLocationCoordinate2D, | |
withZoomLevel zoomLevel: Int, | |
animated: Bool) { | |
let minZoomLevel = min(zoomLevel, 28) | |
let span = coordinateSpan(centerCoordinate, andZoomLevel: minZoomLevel) | |
let region = MKCoordinateRegion(center: centerCoordinate, span: span) | |
setRegion(region, animated: animated) | |
} | |
} | |
let MERCATOR_OFFSET: Double = 268435456 // swiftlint:disable:this identifier_name | |
let MERCATOR_RADIUS: Double = 85445659.44705395 // swiftlint:disable:this identifier_name | |
struct PixelSpace { | |
public var x: Double // swiftlint:disable:this identifier_name | |
public var y: Double // swiftlint:disable:this identifier_name | |
} | |
fileprivate extension MKMapView { | |
func coordinateSpan(_ centerCoordinate: CLLocationCoordinate2D, andZoomLevel zoomLevel: Int) -> MKCoordinateSpan { | |
let space = pixelSpace(fromLongitue: centerCoordinate.longitude, withLatitude: centerCoordinate.latitude) | |
// determine the scale value from the zoom level | |
let zoomExponent = 20 - zoomLevel | |
let zoomScale = pow(2.0, Double(zoomExponent)) | |
// scale the map’s size in pixel space | |
let mapSizeInPixels = self.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 = space.x - (scaledMapWidth / 2) | |
let topLeftPixelY = space.y - (scaledMapHeight / 2) | |
var minSpace = space | |
minSpace.x = topLeftPixelX | |
minSpace.y = topLeftPixelY | |
var maxSpace = space | |
maxSpace.x += scaledMapWidth | |
maxSpace.y += scaledMapHeight | |
// find delta between left and right longitudes | |
let minLongitude = coordinate(fromPixelSpace: minSpace).longitude | |
let maxLongitude = coordinate(fromPixelSpace: maxSpace).longitude | |
let longitudeDelta = maxLongitude - minLongitude | |
// find delta between top and bottom latitudes | |
let minLatitude = coordinate(fromPixelSpace: minSpace).latitude | |
let maxLatitude = coordinate(fromPixelSpace: maxSpace).latitude | |
let latitudeDelta = -1 * (maxLatitude - minLatitude) | |
return MKCoordinateSpan(latitudeDelta: latitudeDelta, longitudeDelta: longitudeDelta) | |
} | |
func pixelSpace(fromLongitue longitude: Double, withLatitude latitude: Double) -> PixelSpace { | |
let x = round(MERCATOR_OFFSET + MERCATOR_RADIUS * longitude * Double.pi / 180.0) | |
let y = round(MERCATOR_OFFSET - MERCATOR_RADIUS * log((1 + sin(latitude * Double.pi / 180.0)) / (1 - sin(latitude * Double.pi / 180.0))) / 2.0) // swiftlint:disable:this line_length | |
return PixelSpace(x: x, y: y) | |
} | |
func coordinate(fromPixelSpace pixelSpace: PixelSpace) -> CLLocationCoordinate2D { | |
let longitude = ((round(pixelSpace.x) - MERCATOR_OFFSET) / MERCATOR_RADIUS) * 180.0 / Double.pi | |
let latitude = (Double.pi / 2.0 - 2.0 * atan(exp((round(pixelSpace.y) - MERCATOR_OFFSET) / MERCATOR_RADIUS))) * 180.0 / Double.pi // swiftlint:disable:this line_length | |
return CLLocationCoordinate2D(latitude: latitude, longitude: longitude) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
space
represents center coordinates.Therefor shouldn't it be rather:
or
right