I need to compute MAX and MIN Latitude and Longitude values from a location with certain distance.
I have thousands of locations stored in CoreData, and I want to show only the ones within 5km from users location.
How can I approach this problem?
I need to compute MAX and MIN Latitude and Longitude values from a location with certain distance.
I have thousands of locations stored in CoreData, and I want to show only the ones within 5km from users location.
How can I approach this problem?
Here's a possible solution:
macros to convert Degrees to Radians
#define deg2rad(degrees) ((degrees) / 180.0 M_PI)
macros to hold my searching distance
#define searchDistance 5.00 //float value in KM
set the minimum and maximum Latitude, Longitude values
float minLat = userLocation.coordinate.latitude - (searchDistance / 69);
float maxLat = userLocation.coordinate.latitude + (searchDistance / 69);
float minLon = userLocation.coordinate.latitude - searchDistance / fabs(cos(deg2rad(userLocation.coordinate.latitude))*69);
float maxLon = userLocation.coordinate.longitude + searchDistance / fabs(cos(deg2rad(userLocation.coordinate.latitude))*69);
create predicate as follows
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"latitude <= %f AND latitude >= %f AND longitude <= %f AND longitude >= %f", maxLat, minLat, maxLon, minLon];
This will create a square around userLocation
and check if a given location falls into its coordinates.
Update: Swift 2.* implementation
First create a function to compute degrees to radians
func deg2rad(degrees:Double) -> Double{
return degrees * M_PI / 180
}
Compute and create minimum and maximum Latitude
and Longitude
values
let searchDistance:Double = 5.00 //float value in KM
let minLat = userLocation.coordinate.latitude - (searchDistance / 69)
let maxLat = userLocation.coordinate.latitude + (searchDistance / 69)
let minLon = userLocation.coordinate.longitude - searchDistance / fabs(cos(deg2rad(userLocation.coordinate.latitude))*69)
let maxLon = userLocation.coordinate.longitude + searchDistance / fabs(cos(deg2rad(userLocation.coordinate.latitude))*69)
Last create NSPredicate
to query CoreData
for locations. In my case I am querying for values latitude
and longitude
but you should change this to match your CoreData
object
let predicate = NSPredicate(format: "latitude <= \(maxLat) AND latitude >= \(minLat) AND longitude <= \(maxLon) AND longitude >= \(minLon)")
Use the CoreLocation method distanceFromLocation:
which returns the distance (in meters) between two points as such:
CLLocation* location = [[CLLocation alloc] initWithLatitude:lat longitude:lon];
if([userLocation distanceFromLocation:location) < searchDistance)
// do something with close point
A suitable predicate can be constructed as:
NSPredicate* predicate = [NSPredicate predicateWithBlock:(BOOL (^)(NSDictionary* target, NSDictionary *bindings)) {
CLLocation* location = [[CLLocation alloc] initWithLatitude:[target[@"lat"] doubleValue] longitude:[target[@"lon"] doubleValue]];
return [userLocation distanceFromLocation:location] < searchDistance;
}];
This has the advantage that it returns the items actually within range, as opposed to the items in a square approximating the range. It's also (probably, we don't know the details) using a more accurate approximation of the range itself. It has the disadvantage that the predicate requires loading every object since it can't be expressed as an sqlite query.