Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS: How to set GMSCoordinateBounds from CoreLocation Coordinates?

The app I am building requires me to ask the user his location, autocomplete, and to make sure that he is indeed nearby. So my idea is to use Google Places Autocomplete, and return the result in a UITableView.

To make sure that the user is near the place he is typing, I want to set the GMSCoordinatesBound to be a certain radius around the user's current location. I know how to get the user's location through CoreLocation, however I am not sure how to convert these coordinates to a GMSCoordinateBounds object that I can use in Google Places autocompleteQuery. Can anybody give me a hint?

Thanks!

like image 429
Charles Panel Avatar asked Aug 26 '15 13:08

Charles Panel


3 Answers

You are now able to restrict the bounds for which the Google Autocomplete ViewController searches. See here: https://developers.google.com/places/ios-api/autocomplete#set_the_gmscoordinatebounds_of_autocomplete

Specifically, you can use CLLocationManager to get your lat and long. Then add offsets to get the bounding region of a map area.

You can do this without having a map in your view. For the case when you are adding an address to a field, for example.

Use https://developers.google.com/places/ios-api/autocomplete#add_a_full-screen_control to setup the full screen search. But add (Swift 2) this code in an IBAction that activates the search autocomplete:

let manager = CLLocationManager()
        manager.startUpdatingLocation()
        let lat = manager.location!.coordinate.latitude
        let long = manager.location!.coordinate.longitude
let offset = 200.0 / 1000.0;
        let latMax = lat + offset;
        let latMin = lat - offset;
let lngOffset = offset * cos(lat * M_PI / 200.0);
        let lngMax = long + lngOffset;
        let lngMin = long - lngOffset;
let initialLocation = CLLocationCoordinate2D(latitude: latMax, longitude: lngMax)
let otherLocation = CLLocationCoordinate2D(latitude: latMin, longitude: lngMin)    
let bounds = GMSCoordinateBounds(coordinate: initialLocation, coordinate: otherLocation)

    let autocompleteController = GMSAutocompleteViewController()

    autocompleteController.autocompleteBounds = bounds
    autocompleteController.delegate = self
    self.presentViewController(autocompleteController, animated: true, completion: nil)

I figured this out with help from the Google Docs and this post: Moving a CLLocation by x meters

Adjust the parameters per the post to change your bounding region. Now I get local search results, not the default New York and beyond.

This assumes you have the Google Places API for iOS set up properly. And, your Google iOS API Key installed (in AppDelegate), the Google client installed and the AutoCompleteViewControllerDelegate extension in your ViewController.

like image 53
D. Rothschild Avatar answered Nov 13 '22 21:11

D. Rothschild


My two cents.

extension GMSCoordinateBounds {
    convenience init(location: CLLocationCoordinate2D, radiusMeters: CLLocationDistance) {
        let region = MKCoordinateRegionMakeWithDistance(location, radiusMeters, radiusMeters)
        self.init(coordinate: region.northWest, coordinate: region.southEast)
    }
}

extension MKCoordinateRegion {
    var northWest: CLLocationCoordinate2D {
        return CLLocationCoordinate2D(latitude: center.latitude + span.latitudeDelta / 2, longitude: center.longitude - span.longitudeDelta / 2)
    }

    var southEast: CLLocationCoordinate2D {
        return CLLocationCoordinate2D(latitude: center.latitude - span.latitudeDelta / 2, longitude: center.longitude + span.longitudeDelta / 2)
    }
}

Using

let bounds = GMSCoordinateBounds(location: coordinate, radiusMeters: 20000)
like image 9
Arsonik Avatar answered Nov 13 '22 22:11

Arsonik


First, some clarifications about what's possible:

  1. The bounds you give to autocomplete will strongly bias the results to be in or near that area, but it's not a hard limit. Users can still type Eiffel Tower, Franc and select the Eiffel Tower in Paris, France even if the location is New Zealand.
  2. The autocomplete bounds are a rectangle, not a circle, so to be pedantic you can't bias to a radius. But a rectangle with the corners a certain distance away from the center will work just fine.

You can offset your coordinate by a fixed distance to make new coordinates for the northeast and southwest corners, e.g. by using https://stackoverflow.com/a/7278293/806600 (answer to "Moving a CLLocation by x meters").

You can then construct a GMSCoordinateBounds from a CLLocationCoordinate2D with those:

GMSCoordinateBounds *bounds = 
  [[GMSCoordinateBounds alloc] initWithCoordinate:northEast
                                       coordinate:southWest];

And then pass that to autocompleteQuery.

like image 2
spiv Avatar answered Nov 13 '22 20:11

spiv