Skip to content

Instantly share code, notes, and snippets.

@jamesmundy
Forked from djad442/MKMapViewZoomLevel.cs
Last active January 21, 2016 14:17
Show Gist options
  • Save jamesmundy/08bac1dbf070b75627e6 to your computer and use it in GitHub Desktop.
Save jamesmundy/08bac1dbf070b75627e6 to your computer and use it in GitHub Desktop.
MonoTouch MKMapView with Zoom Level Property
using System;
using MapKit;
using CoreLocation;
using CoreGraphics;
using System.Drawing;
using Foundation;
namespace BinaryQuest
{
[Register("MKMapViewZoomLevel")]
public class MKMapViewZoomLevel : MKMapView
{
const double MERCATOR_OFFSET = 268435456;
const double MERCATOR_RADIUS = 85445659.44705395d;
public MKMapViewZoomLevel ():base()
{
}
public MKMapViewZoomLevel(IntPtr handle):base(handle)
{
}
private double longitudeToPixelSpaceX(double longitude)
{
return Math.Round(MERCATOR_OFFSET + MERCATOR_RADIUS * longitude * Math.PI / 180.0);
}
private double latitudeToPixelSpaceY(double latitude)
{
return Math.Round(MERCATOR_OFFSET - MERCATOR_RADIUS * Math.Log((1 + Math.Sin(latitude * Math.PI / 180.0)) / (1 - Math.Sin(latitude * Math.PI / 180.0))) / 2.0);
}
private double pixelSpaceXToLongitude (double pixelX)
{
return ((Math.Round(pixelX) - MERCATOR_OFFSET) / MERCATOR_RADIUS) * 180.0 / Math.PI;
}
private double pixelSpaceYToLatitude (double pixelY)
{
return (Math.PI / 2.0 - 2.0 * Math.Atan(Math.Exp((Math.Round(pixelY) - MERCATOR_OFFSET) / MERCATOR_RADIUS))) * 180.0 / Math.PI;
}
private MKCoordinateSpan coordinateSpanWithMapView (MKMapView mapView, CLLocationCoordinate2D centerCoordinate, int zoomLevel)
{
// convert center coordiate to pixel space
double centerPixelX = longitudeToPixelSpaceX(centerCoordinate.Longitude);
double centerPixelY = latitudeToPixelSpaceY(centerCoordinate.Latitude);
// determine the scale value from the zoom level
int zoomExponent = 20 - zoomLevel;
double zoomScale = Math.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
var minLng = pixelSpaceXToLongitude(topLeftPixelX);
var maxLng = pixelSpaceXToLongitude(topLeftPixelX + scaledMapWidth);
var longitudeDelta = maxLng - minLng;
// find delta between top and bottom latitudes
var minLat = pixelSpaceYToLatitude(topLeftPixelY);
var maxLat = pixelSpaceYToLatitude(topLeftPixelY + scaledMapHeight);
var latitudeDelta = -1 * (maxLat - minLat);
// create and return the lat/lng span
MKCoordinateSpan span = new MKCoordinateSpan(latitudeDelta, longitudeDelta);
return span;
}
public void SetCenterCoordinate (CLLocationCoordinate2D centerCoordinate, int zoomLevel, bool animated)
{
// clamp large numbers to 28
zoomLevel = Math.Min(zoomLevel, 28);
// use the zoom level to compute the region
MKCoordinateSpan span = coordinateSpanWithMapView(this, centerCoordinate, zoomLevel);
MKCoordinateRegion region = new MKCoordinateRegion(centerCoordinate, span);
// set the region like normal
this.SetRegion (region, animated);
}
public int ZoomLevel
{
get{
double zoom = 21 - Math.Round(Math.Log(this.Region.Span.LongitudeDelta * MERCATOR_RADIUS * Math.PI / (180.0 * this.Bounds.Size.Width)));
Console.WriteLine("Return Zoom:" + zoom);
return Convert.ToInt32(zoom);
}
}
}
}
@jamesmundy
Copy link
Author

Made some changes to the original to take into account some changes with the Xamarin framework.

Originally taken from: http://troybrant.net/blog/2010/01/set-the-zoom-level-of-an-mkmapview/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment