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()



9 comments:

Luke said...

Hi Jeff, thanks for this. I guess its worth extracting into a function to clean it up a little:

Example on gist

Although, that said, is there a reason why you can't just use the built-in MKCoordinateRegionMakeWithDistance function, e.g.:

#define kOneMileInMeters 1609.344
MKCoordinateRegionMakeWithDistance(newLocation.coordinate, kOneMileInMeters*2, kOneMileInMeters*2)

Perhaps that does something different than what I'd expect.

Heath said...

Yeah, what's wrong with the built-ins?

Jeff LaMarche said...

I'll tell you exactly what's wrong with it...


I didn't know it was there :)

Edwin said...

scrub m65 kamagra attorney lawyer body scrub field jacket lovegra marijuana attorney injury lawyer

charshep said...

Jeff, can you (or any other reader) confirm that setRegion "snaps" to predefined zoom levels? Specifically, it appears that setRegion snaps to the same zoom levels that correspond to the zoom levels used when the user double-taps the map.

I'm trying to restore a previously saved region but this behavior makes it impossible if the saved region was set via a pinch zoom and not a double-tap zoom.

A big clue to me that things are broken on the mapkit side is what occurs if I call regionThatFits on the map's *current* region. It should return the same region (since it obviously fits the map's frame) but it returns the region that corresponds to the next higher predefined zoom level instead.

Any further insight would be appreciated.

Heath said...

@charshep

I've seen similar behavior to what you're talking about. I'm unaware of a workaround.

JeansPilot said...

JeansPilot offers the chance to buy a large variety of men’s and women’s jeans clothing from the world famous Italian Brands.
Online jeans clothing store looks for original fashion clothing sales and clearances of worldwide known designers. We participate in fashion auctions to get the lowest possible price for Top quality Clothes, Shoes and Accessories.
Buy Jeans

SEO Services Consultants said...

Nice information, many thanks to the author. It is incomprehensible to me now, but in general, the usefulness and significance is overwhelming. Thanks again and good luck! Web Design Company

h4ns said...

What youre saying is completely true. I know that everybody must say the same thing, but I just think that you put it in a way that everyone can understand. I also love the images you put in here. They fit so well with what youre trying to say. Im sure youll reach so many people with what youve got to say.

Arsenal vs Huddersfield Town live streaming
Arsenal vs Huddersfield Town live streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Notts County vs Manchester City Live Streaming
Notts County vs Manchester City Live Streaming
Bologna vs AS Roma Live Streaming
Bologna vs AS Roma Live Streaming
Juventus vs Udinese Live Streaming
Juventus vs Udinese Live Streaming
Napoli vs Sampdoria Live Streaming
Napoli vs Sampdoria Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
AS Monaco vs Marseille Live Streaming
AS Monaco vs Marseille Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Technology News | News Today | Live Streaming TV Channels