• Set the Zoom Level of an MKMapView


    If you have ever built a web application using the Google Maps API, you are likely intimately familiar with this line of code:

    map.setCenter(new google.maps.LatLng(37.4419, -122.1419), 13);

    The setCenter JavaScript method takes in the center coordinate and a zoom level. The zoom level, as you might expect, determines how far the map should zoom in. The zoom level ranges from 0 (all the way zoomed out) to some upper value (all the way zoomed in). The max zoom level for a particular area depends on the location (for instance, you can’t zoom in too far on North Korea) and the map type (default, satellite, hybrid, terrain, etc). Typically, the max zoom level for an area is somewhere between 15 – 21.

    Unfortunately, MapKit on the iPhone does not include a way to set the zoom level. Instead, the zoom level is set implicitly by defining the MKCoordinateRegion of the map’s viewport. When initializing the region, you specify the amount of distance the map displays in the horizontal and vertical directions. The zoom level is set implicitly based on these distance values.

    Instead of dealing with this region business, I wrote a category that adds support for setting the zoom level of an MKMapView explicitly. In this post, I’ll give you code you can drop into your own projects and start using immediately. My next post will detail exactly how it works.

    The Code

    Instead of force-feeding you everything I learned while working on this mini-project, I’ll give you the goods up front. The code below defines a category on MKMapView that gives you the ability to set the zoom level for your map:

    // MKMapView+ZoomLevel.h
    #import <MapKit/MapKit.h>
    
    @interface MKMapView (ZoomLevel)
    
    - (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
        zoomLevel:(NSUInteger)zoomLevel
        animated:(BOOL)animated;
    
    @end
    // MKMapView+ZoomLevel.m
    #import "MKMapView+ZoomLevel.h"
    
    #define MERCATOR_OFFSET 268435456
    #define MERCATOR_RADIUS 85445659.44705395
    
    @implementation MKMapView (ZoomLevel)
    
    #pragma mark -
    #pragma mark Map conversion methods
    
    - (double)longitudeToPixelSpaceX:(double)longitude
    {
        return round(MERCATOR_OFFSET + MERCATOR_RADIUS * longitude * M_PI / 180.0);
    }
    
    - (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);
    }
    
    - (double)pixelSpaceXToLongitude:(double)pixelX
    {
        return ((round(pixelX) - MERCATOR_OFFSET) / MERCATOR_RADIUS) * 180.0 / M_PI;
    }
    
    - (double)pixelSpaceYToLatitude:(double)pixelY
    {
        return (M_PI / 2.0 - 2.0 * atan(exp((round(pixelY) - MERCATOR_OFFSET) / MERCATOR_RADIUS))) * 180.0 / M_PI;
    }
    
    #pragma mark -
    #pragma mark Helper methods
    
    - (MKCoordinateSpan)coordinateSpanWithMapView:(MKMapView *)mapView
        centerCoordinate:(CLLocationCoordinate2D)centerCoordinate
        andZoomLevel:(NSUInteger)zoomLevel
    {
        // convert center coordiate to pixel space
        double centerPixelX = [self longitudeToPixelSpaceX:centerCoordinate.longitude];
        double centerPixelY = [self 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 top-left pixel
        double topLeftPixelX = centerPixelX - (scaledMapWidth / 2);
        double topLeftPixelY = centerPixelY - (scaledMapHeight / 2);
        
        // find delta between left and right longitudes
        CLLocationDegrees minLng = [self pixelSpaceXToLongitude:topLeftPixelX];
        CLLocationDegrees maxLng = [self 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 latitudeDelta = -1 * (maxLat - minLat);
        
        // create and return the lat/lng span
        MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
        return span;
    }
    
    #pragma mark -
    #pragma mark Public methods
    
    - (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
        zoomLevel:(NSUInteger)zoomLevel
        animated:(BOOL)animated
    {
        // clamp large numbers to 28
        zoomLevel = MIN(zoomLevel, 28);
        
        // use the zoom level to compute the region
        MKCoordinateSpan span = [self coordinateSpanWithMapView:self centerCoordinate:centerCoordinate andZoomLevel:zoomLevel];
        MKCoordinateRegion region = MKCoordinateRegionMake(centerCoordinate, span);
        
        // set the region like normal
        [self setRegion:region animated:animated];
    }
    
    @end

    If you’re wondering why this works, check out my next post where I describe in gruesome detail the math behind the code.

    On the other hand, if you don’t really care how it works, just that it does work, copy and paste away, my friend.

     

    Test the Code

    To test the category, assuming you have a view controller with an MKMapView instance, you can use the following code:

    // ZoomLevelTestViewController.m
    #import "MKMapView+ZoomLevel.h"
    
    #define GEORGIA_TECH_LATITUDE 33.777328
    #define GEORGIA_TECH_LONGITUDE -84.397348
    
    #define ZOOM_LEVEL 14
    
    - (void)viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];
        
        CLLocationCoordinate2D centerCoord = { GEORGIA_TECH_LATITUDE, GEORGIA_TECH_LONGITUDE };
        [mapView setCenterCoordinate:centerCoord zoomLevel:ZOOM_LEVEL animated:NO];
    }

    And, viola! Your map should zoom in to where you can see the Georgia Tech campus.

    原文地址:http://troybrant.net/blog/2010/01/set-the-zoom-level-of-an-mkmapview/

  • 相关阅读:
    Algs4-1.3.37Josephus问题
    Algs4-1.3.35随机队列
    Algs4-1.3.33一个双向队列Deque的可变长环形数组实现
    Algs4-1.3.34随机背包
    Algs4-1.3.33一个双向队列Deque-双向链表实现
    Algs4-1.3.32链表实现Stack和Queue的合体Steque
    Algs4-1.3.31实现双向链表
    Algs4-1.3.30反转链表
    C语言多级指针
    spring mvc@ModelAttribute与@SessionAttributes的执行流程
  • 原文地址:https://www.cnblogs.com/solitary/p/2744920.html
Copyright © 2020-2023  润新知