1

I am developing iOS app, in which i want to find all locations within a some radius.

Is there any way in objective-c that will allow me to specify a fixed radius and a location, and that will tell me which locations are within that radius ?

I have done some researching and i got this code snippet,

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder reverseGeocodeLocation:locationManager.location
                   completionHandler:^(NSArray *placemarks, NSError *error) 
                   {
                       NSLog(@"reverseGeocodeLocation:completionHandler: Completion Handler called!");

                       if (error)
                       {
                           NSLog(@"Geocode failed with error: %@", error);
                           return;
                       }


                       CLLocationDistance radius = 30;
                       CLLocation* target = [[CLLocation alloc] initWithLatitude:51.5028 longitude:0.0031];

                       NSArray *locationsWithinRadius = [placemarks objectsAtIndexes:
                                                         [placemarks indexesOfObjectsPassingTest:
                                                          ^BOOL(id obj, NSUInteger idx, BOOL *stop) {

                                                              return [(CLLocation*)obj distanceFromLocation:target] < radius;

                                                          }]];

                       NSLog(@"locationsWithinRadius=%@",locationsWithinRadius);


                   }];

but it gets crashes and shows error:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CLPlacemark distanceFromLocation:]:

Am i going on right way ? is this a way, to find all locations from my specified locations ?

Thanks in advance.

EDIT:

NSArray *testLocations = @[[[CLLocation alloc] initWithLatitude:19.0759 longitude:72.8776]];

                   CLLocationDistance maxRadius = 3000; // in meters
                   CLLocation *targetLocation = [[CLLocation alloc] initWithLatitude:newLocation.coordinate.latitude longitude:newLocation.coordinate.longitude]; //Current location coordinate..

                   NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(CLLocation *testLocation, NSDictionary *bindings) {
                       return ([testLocation distanceFromLocation:targetLocation] <= maxRadius);
                   }];

                   NSArray *closeLocations = [testLocations filteredArrayUsingPredicate:predicate];

                   NSLog(@"closeLocations=%@",closeLocations);

When i log my closeLocations array it shows null(Empty) value. Coordinate which i provided in testLocations is near to my current location.

Krunal
  • 6,440
  • 21
  • 91
  • 155
  • You have a list of locations (coordinates) and you want to find which are within a set distance of another coordinate? You don't need to geocode for that. What is your source data? – Wain Jul 09 '13 at 13:03
  • I have latitude and longitude of all locations in my DB. i want to find which lat and long are near to my current `latitude` and `longitude`. – Krunal Jul 09 '13 at 13:10
  • what's the wrong in my code ? what it would be my `placemarks array` should conatin all location name ? – Krunal Jul 09 '13 at 13:13

1 Answers1

4

What you're trying to do in your code is geocoding, this is the process of translating coordinates to addresses and isn't what you want to do. Instead you need to more basic coordinate bounding. You could use the distanceFromLocation: method in your code above and just iterate through your coordinates, converting them into CLLocation objects (if they aren't already) and then checking the distance to your center point.

Rather than using indexesOfObjectsPassingTest, I'd probably use filteredArrayUsingPredicate and a predicate created with predicateWithBlock to do your distance check (unless you actually want the indices for some reason).


NSArray *testLocations = @[ [[CLLocation alloc] initWithLatitude:11.2233 longitude:13.2244], ... ];

CLLocationDistance maxRadius = 30; // in meters
CLLocation *targetLocation = [[CLLocation alloc] initWithLatitude:51.5028 longitude:0.0031];

NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(CLLocation *testLocation, NSDictionary *bindings) {
    return ([testLocation distanceFromLocation:targetLocation] <= maxRadius);
}];

NSArray *closeLocations = [testLocations filteredArrayUsingPredicate:predicate];
Wain
  • 118,658
  • 15
  • 128
  • 151
  • excellent exaplanation... :) can you show me the code snippet for the same ? – Krunal Jul 09 '13 at 13:20
  • At very first line `testLocations` will be array of my latitude and longitude from my DB ? – Krunal Jul 09 '13 at 13:44
  • Yes, but ensure that are instances of `CLLocation`. So you may need to use `initWithLatitude:longitude:` to generate the array. – Wain Jul 09 '13 at 13:53
  • it crashes, see my **EDIT** in question it shows `Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFConstantString distanceFromLocation:]:` – Krunal Jul 09 '13 at 14:05
  • So, your array contains `NSString` instances, which aren't the same as (or somehow converted into) `CLLocation` instance, so it breaks. Fill the array with `CLLocation` instances instead. – Wain Jul 09 '13 at 14:09
  • how can i add as `CLLocation` instance in my array ? – Krunal Jul 09 '13 at 14:14
  • In this line, do i need to write `lat` and `long` of my current location ? `CLLocation *targetLocation = [[CLLocation alloc] initWithLatitude: 51.5028 longitude:0.0031];` – Krunal Jul 09 '13 at 14:25
  • You need to get your source info from the DB and create the location objects. And yes, also for your current location. To replace the currently hard coded values. – Wain Jul 09 '13 at 14:26
  • can you please see my new EDIT in the question. – Krunal Jul 10 '13 at 07:00
  • In the predicate, add a log statement to see what happens: `NSLog(@"distance: %f", [testLocation distanceFromLocation:targetLocation]);` – Wain Jul 10 '13 at 07:45
  • log Shows: `distance: 1329.278670` – Krunal Jul 10 '13 at 08:02
  • how to pass multiple values here in your answer, `NSArray *testLocations = @[ [[CLLocation alloc] initWithLatitude:11.2233 longitude:13.2244], ... ];` i have lot of latitude and londitude in my DB, i want to compare with all with my current location. – Krunal Jul 10 '13 at 08:06
  • a for loop, iterate the DB contents and create the locations then add them to a mutable array... – Wain Jul 10 '13 at 08:11
  • Here are some values which i fetched from DB,`latArr=[NSArray arrayWithObjects:@"19.1405",@"19.1031",@"19.0726",@"19.0759", nil];` now how should i add this values to `testLocations` array ? so that i can also compare this values with my current location.. – Krunal Jul 10 '13 at 08:19
  • Just i want to know, how can i pass multiple values here `NSArray *testLocations = @[ [[CLLocation alloc] initWithLatitude:11.2233 longitude:13.2244], ... ];` the values are fetched from my DB, I already fetched all the values from DB, but now how should i pass fetched values to this `testLocations` array ? – Krunal Jul 10 '13 at 08:28
  • Is that just an array of latitudes? Do you have another one of longitudes? Think about how you might loop over the array contents. – Wain Jul 10 '13 at 08:32
  • i have two different array of `latArr` and `longArr` i have tried this but it is not working, `for (int i=0; i<[latArr count]; i++) { testLocations = @[[[CLLocation alloc] initWithLatitude:[[latArr objectAtIndex:i]doubleValue] longitude:[[longArr objectAtIndex:i]doubleValue]]]; //lat and long which fetched from DB }` – Krunal Jul 10 '13 at 08:50
  • because you aren't adding the items to the array, you're replacing the array each time (with a new one, and throwing the old one away) – Wain Jul 10 '13 at 08:51
  • Work is done... thnax for the help. :) only last problem dude, i am getting data like this, `[array objectAtIndex:0]= "<+19.14050000,+73.00805000> +/- 0.00m (speed -1.00 mps / course -1.00) @ 10/07/13 4:03:27 PM India Standard Time",` and `[array objectAtIndex:1]= "<+19.10310000,+73.01130000> +/- 0.00m (speed -1.00 mps / course -1.00) @ 10/07/13 4:03:27 PM India Standard Time",` i want only latitude and longitude to be stored in my array. – Krunal Jul 10 '13 at 10:44
  • That's just the logged description of the location object, not a problem. – Wain Jul 10 '13 at 10:45
  • no dude i want it beacuse i want to pass this lat and long to my new services, is there any way to extract lat and long from this array location ? – Krunal Jul 10 '13 at 10:50
  • 2
    `CLLocation` provides a `coordinate` property – Wain Jul 10 '13 at 10:53