Skip to content

Instantly share code, notes, and snippets.

@djad442
Created March 8, 2013 08:36
Show Gist options
  • Save djad442/5115021 to your computer and use it in GitHub Desktop.
Save djad442/5115021 to your computer and use it in GitHub Desktop.
MonoTouch MKMapView with Zoom Level Property
using System;
using MonoTouch.MapKit;
using MonoTouch.CoreLocation;
using System.Drawing;
using MonoTouch.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
SizeF 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

This is very handy - just what I needed. Thanks for taking the time to do this!

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