Calculate the radius in meters using mapkit - iphone

I need to know the distance (in kilometers) from center map to the other side of the screen, (and if the zoom change the distance will change).
I need to implement this feature in this function
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{
}
Any ideas how i can do this?
Thanks

MkMapView has properties named centerCoordinate(CLLocationCoordinate2D) and region (MKCoordinateRegion). Region is a struct that:
typedef struct {
CLLocationDegrees latitudeDelta;
CLLocationDegrees longitudeDelta;
}MKCoordinateSpan
You should be able to create another point, based on centerCoordinate, let's say, by adding latitudeDelta to you latitude property or centerCoordinate, and calculate distance using the method of CLLocation:
- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location
Something like this
MkMapView * mapView; // init somewhere
MKCoordinateRegion region = mapView.region;
CLLocationCoordinate2D centerCoordinate = mapView.centerCoordinate;
CLLocation * newLocation = [[[CLLocation alloc] initWithLatitude:centerCoordinate.latitude+region.span.latitudeDelta longitude:centerCoordinate.longitude] autorelease];
CLLocation * centerLocation = [[[CLLocation alloc] initWithLatitude:centerCoordinate.latitude:longitude:centerCoordinate.longitude] autorelease];
CLLocationDistance distance = [centerLocation distanceFromLocation:newLocation]; // in meters
And just calculate each time a delegate fires a certain method (decide which you need: MKMapViewDelegate)

Because rectangles aren't circles you can't get a radius.
But you can still get the furthest distance from the center of a region.
Reusing the same idea as above but embeded in a swift extension.
extension MKCoordinateRegion {
func distanceMax() -> CLLocationDistance {
let furthest = CLLocation(latitude: center.latitude + (span.latitudeDelta/2),
longitude: center.longitude + (span.longitudeDelta/2))
let centerLoc = CLLocation(latitude: center.latitude, longitude: center.longitude)
return centerLoc.distanceFromLocation(furthest)
}
}
Usage
let radius = mapView.region.distanceMax()

Related

How to find the radius of visible MKMapView visible screen area?

I want to know the radius of visible area in iphone screen, as I will zoomout and zoom in the visible area will change, so I want to know the radius of that particular area, how can I do it?
Its not radius what is required.
You need to use the region parameter from mapView.
Check out apple docs, it is pretty much clear from those.
Go thru this tutorial. It will help you a lot
icode blog mapkit demo
specifically you need to set something like this..
MKCoordinateSpan span = [self coordinateSpanWithMapView:self centerCoordinate:centerCoordinate andZoomLevel:zoomLevel];
MKCoordinateRegion region = MKCoordinateRegionMake(centerCoordinate, span);
[self setRegion:region animated:animated];
where span can be calculated as
- (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;
}
Cheers :)
I might be misunderstanding the question, but isn't it as simple as:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
CGFloat latD = mapView.region.span.latitudeDelta;
CGFloat lngD = mapView.region.span.longitudeDelta;
NSLog(#"This is the latitude delta of the visible map: %f", latD);
NSLog(#"This is the longitude delta of the visible map: %f", lngD);
}

MKCoordinateRegionMakeWithDistance does not set the correct region on the MapView

I have this code :
- (void)viewDidLoad
{
[super viewDidLoad];
CLLocationCoordinate2D userLocation = CLLocationCoordinate2DMake(48.9793946200, 2.4726272850);
CLLocationDistance dist1 = 636.9887048804;
CLLocationDistance dist2 = 900.8380655203;
CLLocationDistance dist = dist1;
[self.myMapView setRegion:MKCoordinateRegionMakeWithDistance(userLocation, dist, dist) animated:YES];
// TEST
// ------------------------------------------------------------
MKCoordinateRegion region = self.myMapView.region;
CLLocationDegrees lat = region.center.latitude;
CLLocationDegrees lon = region.center.longitude - region.span.longitudeDelta/2;
CLLocation *west = [[[CLLocation alloc] initWithLatitude:lat longitude:lon] autorelease];
NSLog(#"User location: lat : %.10lf long : %.10lf", userLocation.latitude, userLocation.longitude);
NSLog(#"distance set: %.10lfm", dist);
NSLog(#"center: lat : %.8lf long : %.8lf", region.center.latitude, region.center.longitude);
CLLocation* centerRegion = [[[CLLocation alloc] initWithLatitude:region.center.latitude longitude:region.center.longitude] autorelease];
NSLog(#"distance to western boundary: %.2lfm", [centerRegion distanceFromLocation:west]);
lat = region.center.latitude - region.span.latitudeDelta/2 ;
lon = region.center.longitude;
CLLocation *north = [[[CLLocation alloc] initWithLatitude:lat longitude:lon] autorelease];
NSLog(#"distance to western boundary: %.2lfm", [centerRegion distanceFromLocation:north]);
// ------------------------------------------------------------
}
When setting dist = dist1, that gives :
User location: lat : 48.9793946200 long : 2.4726272850
distance set: 636.9887048804m
center: lat : 48.97937199 long : 2.47269630
distance to western boundary: 500.44m
distance to western boundary: 650.57m
When setting dist = dist2, that gives :
User location: lat : 48.9793946200 long : 2.4726272850
distance set: 900.8380655203m
center: lat : 48.97937199 long : 2.47269630
distance to western boundary: 500.44m
distance to western boundary: 650.57m
What's the problem here ? Why do I have the same display with 2 different distances ?
Final question : How can I be sure to display the wanted meters on the map, at minimum for horizontal and vertical visual (with or without animation of course) ?
If I understand it correctly, you want to tell the mapView "give me a map which is 636m across" or "give me a map which is 900m across". But the map gives you the same distance across for both of these.
When you set a map region, you generally don't get back exactly what you ask for, but instead a best fit. The map view looks at the region you requested, then creates a region which fits your region inside it. The problem is that the map view doesn't zoom exactly to your requested region, it finds the highest zoom level that allows all your region to be visible. It won't use an in-between zoom level. This is why when you use setRegion: the map always looks crisp. You can manually set an in-between zoom level by pinching in or out, but not (as far as I know) programatically.
Note too that the map view might change the actual region variable you pass to it. Here's the docs:
When setting a new region, the map may adjust the value in the region parameter so that it fits the visible area of the map precisely. This is normal and is done to ensure that the value in the region property always reflects the visible portion of the map. However, it does mean that if you get the value of that property right after calling this method, the returned value may not match the value you set. (You can use the regionThatFits: method to determine the region that will actually be set by the map.)
You can see the difference in regions by logging the region you give it, and the one the map view actually sets (although I didn't see the passed myRegion change):
MKCoordinateRegion myRegion = MKCoordinateRegionMakeWithDistance(userLocation, dist, dist);
NSLog(#"Passed: %f %f", myRegion.span.latitudeDelta, myRegion.span.longitudeDelta);
[self.mapView setRegion:myRegion animated:YES];
NSLog(#"Passed 2: %f %f", myRegion.span.latitudeDelta, myRegion.span.longitudeDelta);
NSLog(#"Set: %f %f", mapView.region.span.latitudeDelta, mapView.region.span.longitudeDelta);
> Passed: 0.005728 0.008702
> Passed 2: 0.005728 0.008702
> Set: 0.012957 0.013733
If you bump your distance up to 1200m, you'll be able to see the next zoom level.
BTW, there's a small error in your code:
NSLog(#"distance to western boundary: %.2lfm", [centerRegion distanceFromLocation:north]);
should be
NSLog(#"distance to northern boundary: %.2lfm", [centerRegion distanceFromLocation:north]);
One possible cause of this is that the region you are specifying has square aspect ratio while your MKMapView probably has a rectangular one.
When you set the region MKMapView will not use it exactly as it is, but will modify it so that:
its aspect ratio corresponds to that of the view
the new region contains the specified one
Thus if your view has a width:height aspect ratio of 2:1, then the west/east boundaries would be 200m from the center while north/south boundaries 100m from the center.
Something to try after setting the region as above:
MKCoordinateRegion region = self.mapView.region;
CLLocationDegrees lat = region.center.latitude;
CLLocationDegrees lon = region.center.longitude - region.span.longitudeDelta/2;
CLLocation *west = [[CLLocation alloc] initWithLatitude:lat longitude:lon];
NSLog(#"distance to western boundary: %.2lfm", [userLocation distanceFromLocation:west]);
lat = region.center.latitude + region.span.latitudeDelta/2
lon = region.center.longitude;
CLLocation *north = [[CLLocation alloc] initWithLatitude:lat longitude:lon];
NSLog(#"distance to northern boundary: %.2lfm", [userLocation distanceFromLocation:north]);
One of those should be 100m. If not, I would be interested to see what they are.
P.S. The code above has not been tested in anyway.

Calculate distance between two place using latitude-longitude in gmap for iPhone [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
GPS coordinates in degrees to calculate distances
How to Calculate distance between two place using latitude-longitude in gmap for iPhone?
Calculate distance between two place using latitude-longitude in gmap for iPhone
You have to use Core Location Framework. So don't forget to Add & import Core Location Framework.
Objective-C
#import <CoreLocation/CoreLocation.h>
CLLocation *locA = [[CLLocation alloc] initWithLatitude:lat1 longitude:long1];
CLLocation *locB = [[CLLocation alloc] initWithLatitude:lat2 longitude:long2];
CLLocationDistance distance = [locA distanceFromLocation:locB];
//distance in Meters
//1 meter == 100 centimeter
//1 meter == 3.280 feet
//1 square meter == 10.76 square feet
[locA release];
[locB release];
Swift
import CoreLocation
let locA = CLLocation(latitude: lat1, longitude: long1)
let locB = CLLocation(latitude: lat2, longitude: long2)
let distance = locA.distance(from: locB)
if you have the location parameter, create 2 CLLocations and use [location1 distanceFromLocation:location2] method.

MapView regionThatFits set using horizontalAccuracy

I'm looking for a method to convert meters to a mapview region.
CLLocation's horizontalAccuracy is a double, representing the accuracy in meters. regionThatFits: takes an MKCoordinateRegion which has a span with longitudeDelta and latitudeDelta. How can I convert meters to a longitude/latitude span?
Found an answer. It seems that 1 degree of latitude is equal to around 111 kilometers, or 111120 meters
- (MKCoordinateRegion)regionForAccuracyOfLocation:(CLLocation *)location
{
CLLocationDegrees spanInDegrees = (CLLocationDegrees) (location.horizontalAccuracy / 222240);
MKCoordinateSpan span = MKCoordinateSpanMake(spanInDegrees, spanInDegrees) ;
CLLocationCoordinate2D coordinate = location.coordinate;
MKCoordinateRegion region = MKCoordinateRegionMake(coordinate, span);
return region;
}

How can I center a UIMapView around an array of MKAnnotation?

How can I center a UIMapView around an array of MKAnnotation?
First find the minimum and maximum latitude and longitude from your array of annotations. Then you can set the region:
MKCoordinateRegion extents;
extents.center.latitude = (maxLat + minLat)/2.0;
extents.center.longitude = (maxLong + minLong)/2.0;
extents.span.latitudeDelta = (maxLat - minLat);
extents.span.longitudeDelta = (maxLong - minLong);
MKCoordinateRegion fittedRegion = [mapView regionThatFits:extents];
[mapView setRegion:fittedRegion animated:YES];