Showing posts with label MapKit. Show all posts
Showing posts with label MapKit. Show all posts

Monday, November 9, 2009

MKMapView Category

I've been working with MapKit quite a bit the last few days as I finish the chapter on MapKit. I was surprised to find that the map view didn't have a method for telling you whether specific coordinates were currently being shown on screen. The map view has a method to tell you whether the user's current location is visible, but I couldn't find one to that indicated if any arbitrary coordinates were currently visible on screen.

This category rectifies that.

MKMapView-CoordsDisplay.h
#import <MapKit/MapKit.h>

@interface MKMapView(CoordsDisplay)
- (BOOL)coordinatesInRegion:(CLLocationCoordinate2D)coords;
@end


MKMapView-CoordsDisplay.m
#import "MKMapView-CoordsDisplay.h"

@implementation MKMapView(CoordsDisplay)
- (BOOL)coordinatesInRegion:(CLLocationCoordinate2D)coords
{
CLLocationDegrees leftDegrees = self.region.center.longitude - (self.region.span.longitudeDelta / 2.0);
CLLocationDegrees rightDegrees = self.region.center.longitude + (self.region.span.longitudeDelta / 2.0);
CLLocationDegrees bottomDegrees = self.region.center.latitude - (self.region.span.latitudeDelta / 2.0);
CLLocationDegrees topDegrees = self.region.center.latitude + (self.region.span.latitudeDelta / 2.0);

return leftDegrees <= coords.longitude && coords.longitude <= rightDegrees && bottomDegrees <= coords.latitude && coords.latitude <= topDegrees;
}

@end

Wednesday, November 4, 2009

MapView Hint

Here's a trick to help you deal with MapViews. In order to set the zoom level in a MapView, you have to specify a region for it to show. The region includes a span, which specifies in degrees latitude and longitude how much area to show. You can get an approximate conversion of degrees longitude and latitude to miles using the following constants and macros:

#define kApproxRadiusOfEarthInMiles                     3963.1676
#define kApproxSizeOfOneDegreeLatitudeInMiles 68.71
#define kApproxSizeOfOneDegreeLongitudeAtLatitude(lat) ((M_PI/180.0)* kApproxRadiusOfEarthInMiles *cos(lat))

Once you have these, specifying a region to show is relatively easy. Let's say I want to show approximately a half mile around a given location in my Core Location delegate method (I know MapView will track location for you, this is just a convenient way to show how to use the macros):

- (void)locationManager:(CLLocationManager *)manager 
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {


MKCoordinateSpan viewSpan;

viewSpan.latitudeDelta = 0.5 / kApproxSizeOfOneDegreeLatitudeInMiles;
viewSpan.longitudeDelta = 0.5 / kApproxSizeOfOneDegreeLongitudeAtLatitude(newLocation.coordinate.latitude);
MKCoordinateRegion viewRegion;
viewRegion.center = newLocation.coordinate;
viewRegion.span = viewSpan;

MKCoordinateRegion adjustedRegion = [mapView regionThatFits:viewRegion];
[mapView setRegion:adjustedRegion animated:YES];
}

These aren't exact, but they should be close enough. Although the distance represented by one degree latitude isn't a constant, it varies by a small enough amount as to be insignificant for this calculation. For longitude, a degree at the equator is substantially larger than one degree in the arctic circle, so we have to use a little math to get the approximate number.

That's it. With this code, it will zoom down to the current location and show roughly a quarter mile on each side of the current location. The call to adjust region will change that a little to match the view's aspect ratio. Want to zoom out? Change 0.5 to a larger value. If you use 10, it will show about five miles to each side of the current location.

Whoops! Turns out there's already a built-in function that works similarly to these macros: MKCoordinateRegionMakeWithDistance()