objective-c google maps delegate method reverseGeocodeCoordinate method - ios

I'm not sure if this is new with google maps but I think it looks like this version of Google Maps for iOS already has a reverse geocoding method...one which I can't really figure out how to use. In their documentation page, under section Camera Position, they have a function, but it doesn't look like the one that came with the SDK...or maybe there's something I don't understand here. Can someone help out? Here's the function that comes up in XCode:
- (void)reverseGeocodeCoordinate:(CLLocationCoordinate2D)coordinate
completionHandler:(GMSReverseGeocodeCallback)handler{}
How can I use that if I have my coordinates in an array? How do I get the address and country and all the possible results?
By the way, this is what they have...how does it compare:
- (void)mapView:(GMSMapView *)mapView
idleAtCameraPosition:(GMSCameraPosition *)cameraPosition {
id handler = ^(GMSReverseGeocodeResponse *response, NSError *error) {
if (error == nil) {
GMSReverseGeocodeResult *result = response.firstResult;
GMSMarker *marker = [GMSMarker markerWithPosition:cameraPosition.target];
marker.title = result.addressLine1;
marker.snippet = result.addressLine2;
marker.map = mapView;
}
};
[geocoder_ reverseGeocodeCoordinate:cameraPosition.target completionHandler:handler];
}

You can try this code
[[GMSGeocoder geocoder]reverseGeocodeCoordinate:CLLocationCoordinate2DMake(latitude, longitude)
completionHandler:^(GMSReverseGeocodeResponse * response, NSError *error){
for(GMSReverseGeocodeResult *result in response.results){
NSLog(#"addressLine1:%#", result.addressLine1);
NSLog(#"addressLine2:%#", result.addressLine2);
}
}];

Related

MKLocalSearch not working like Apple Maps search?

I have created a MapKit and trying to play around with MKLocalSearch. One thing I noticed in comparison to Apple Maps, is that mklocalsearch is restricted to 10 results. So how does Apple Maps display 15 suggestions under the search bar?
Okay, on to an example. Im trying to find "Barcelona." In Apple Maps it will be suggested after writing just "barc" and it will stay on the suggestion list throughout typing barcelona.
Now in my own Map view, I actually have to type in the full Barcelona to get the suggestion: Spain, Barcelona. On my way I get other suggestions, but nothing like Spain, Barcelona and not like Apple maps.
Any insight on how to get it working and to why Apple Maps work differently (spec. the 15 results vs 10 with mklocalseach)
Here is the code called on textField Changes:
- (IBAction)searchFieldChanged:(UITextField *)sender {
if(self.locationTextfield.text.length>0)
self.tableView.hidden = NO;
else
self.tableView.hidden = YES;
NSString *query = self.locationTextfield.text;
// Create and initialize a search request object.
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = query;
request.region = self.mapsView.region;//we dont want region-specific search results!
//request.region = MKCoordinateRegionMakeWithDistance(self.mapsView.userLocation.location.coordinate,40000000, 15000000);
// Create and initialize a search object.
MKLocalSearch *search = [[MKLocalSearch alloc] initWithRequest:request];
// Start the search and display the results as annotations on the map.
[search startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error)
{
[placeMarks removeAllObjects];
NSLog(#"p-count: %lu", response.mapItems.count);
for (MKMapItem *item in response.mapItems) {
[placeMarks addObject:item.placemark];
self.tempPlacemark = item.placemark;
NSLog(#"placemark: %#", item.placemark);//.location.coordinate.latitude);
}
//if(placemarks.count==0)
// appDelegate.staticPlacemark = nil;
//[self.mapsView removeAnnotations:[self.mapsView annotations]];
//[self.mapsView showAnnotations:placemarks animated:NO];
[self.tableView reloadData];
}];
}
What you do is a MKLocalSearch using a MKLocalSearchRequest. What Apple in its macOS and iOS map apps does is using the newer MKLocalSearchCompleter class to obtain autocompletion suggestions. These suggestions are used for realtime search and displayed in a UITableView. When the user selects one entry that suggestion is used to initialize a MKLocalSearchRequest to obtain detailled information about this location.

Is it possible to grab information such as city based on the center of the mapview

I have a MKMapView and want to grab the cities name based on the center of the MKMapView. I do not want to drop any pins or annotations at all. Just automatically grab the data based on center of MKMapView location. I know there is this method '[placemarkName locality]'. But is there a way without using a placemark?
You could just do a reverseGeocodeLocation (effective iOS 5+) from the centerCoordinate of the map view. For example, I could do something like:
CLLocationCoordinate2D center = self.mapView.centerCoordinate;
CLGeocoder *coder = [[CLGeocoder alloc] init];
[coder reverseGeocodeLocation:[[CLLocation alloc] initWithLatitude:center.latitude longitude:center.longitude] completionHandler:^(NSArray *placemarks, NSError *error) {
self.cityLabel.text = [[placemarks firstObject] locality];
}];
This admittedly, returns an array of placemarks, but you don't have to do anything with them after you extract the city's name.

Annotation along route in MapKit

I'm using MapKit to display directions between locations, and I'm looking for a way to add an annotation that works similarly to the route annotation in the Apple Maps app, where annotations are showing each route's travel time (as shown in the image below). I am already drawing the directions correctly, the problem at hand is how to calculate a pair of coordinates along the route. That is, where to drop the annotation.
I thought about somehow using the MKDirection (which contains complete directions, step by step) but I am not sure how I would generate a pair of coordinates that are somewhere in the middle of the route.
I have not been able to find any kind of support for this in the MapKit documentation. Any ideas?
This is how I generate the route and display it.
- (void)generateRoute {
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
request.source = [MKMapItem mapItemForCurrentLocation];
request.destination = self.destinationMapItem;
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error) {
// Handle Error
} else {
[self showRoute:response];
}
}];
}
- (void)showRoute:(MKDirectionsResponse *)response {
[self.mapView removeOverlays:self.mapView.overlays];
for (MKRoute *route in response.routes)
{
[self.mapView addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
}
[self fitRegionToRoute];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id < MKOverlay >)overlay
{
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
renderer.strokeColor = [UIColor blueColor];
renderer.alpha = 0.7;
renderer.lineWidth = 4.0;
return renderer;
}
Questioner's edit:
Finally made it work with the help of this answer. I added this to the code below, where it says Here do the magic:
MKMapPoint middlePoint = route.polyline.points[route.polyline.pointCount/2];
[self createAndAddAnnotationForCoordinate:MKCoordinateForMapPoint(middlePoint)];
Original answer:
I don't know whether this will work or not. Just my idea on your question.
I guess you would have created the routes as following
(Check my inline comments)
MKDirectionsRequest *request =
[[MKDirectionsRequest alloc] init];
request.source = [MKMapItem mapItemForCurrentLocation];
request.destination = _destination;
request.requestsAlternateRoutes = NO;
MKDirections *directions =
[[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error) {
// Handle error
} else {
for (MKRoute *route in response.routes)
{
[_routeMap addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
//Here do the magic
//MKPolyline confronts to MKOverlay so you can get the coordinate like
//route.polyline.coordinate once you get the coordinate then you can build
//a annotation. A annotation is nothing but a coordinate with some title.
//According to MKOverlay coordinate property it justs gives you the
//center point of the overlay area
[self createAndAddAnnotationForCoordinate:route.polyline.coordinate]
}
}
}];
Adding Annotation
-(void) createAndAddAnnotationForCoordinate : (CLLocationCoordinate2D) coordinate{
MyAnnotation* annotation= [[MyAnnotation alloc] init];
annotation.coordinate = coordinate;
annotation.title = #"Any Title";
annotation.subtitle = #"Any Subtitle";
[yourMap addAnnotation: annotation];
}
If you want to know the middle for swift you can use the following code :
MKCoordinateForMapPoint(route.polyline.points()[route.polyline.pointCount/2])
Exemple of use :
directions.calculateDirectionsWithCompletionHandler ({
(response: MKDirectionsResponse?, error: NSError?) in
if error == nil {
self.showRoute(response!)
}
else{
print("some error")
}
})
func showRoute(response:MKDirectionsResponse){
for route in response.routes {
self.map.addOverlay(route.polyline, level: MKOverlayLevel.AboveRoads)
self.map.setCenterCoordinate(route.polyline.coordinate, animated: true)
self.map.setRegion(MKCoordinateRegionMakeWithDistance(route.polyline.coordinate, route.distance*0.75, route.distance*0.75), animated: true)
let routeAnnotation = MKPointAnnotation()
routeAnnotation.coordinate = MKCoordinateForMapPoint(route.polyline.points()[route.polyline.pointCount/2])
map.addAnnotation(routeAnnotation)
}
}
Perhaps not the most efficient way, but should still likely be quick, would be to calculate the midpoint of your start and end points (i.e., average their lats and longs). Then, iterate through your polyline points checking the distance from each to that midpoint. Take the closest match.
Even if the line is wildly curved, the midpoint will be directly between the ends. Some point on the wild curve is the closest to that external midpoint and is likely a good place to put the annotation.
Once you have an MKRoute, the approximate centre-point can be found using:
route.polyline.coordinate
This returns a CLLocationCoordinate2D that you can use to centre your annotation.
Appreciate this is an old question but I'd been searching for something like this for a while and ended up calculating the centre manually. Turns out it's very straightforward since iOS 8.
I suggest you see this , Integrated with routing.

google search places autocomplete specific to country in ios

I am working on Google Places AutoComplete Service where i need to filter the places specific to country and found this.
It is working good untill when i pass a parameter components=country:se to filter the autocomplete field its response is REQUEST_DENIED
NSMutableString *url = [NSMutableString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/autocomplete/json?input=%#&components=country:se&sensor=%#&key=%#",
[input stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
SPBooleanStringForBool(sensor), key];
I need the autocomplete to give suggestion specific to country.
Thanks
This works fine for me.
You can set this by adding the bounds for the region by adding its extreme top left and bottom right location points of the the Geographical area.
like for USA i used.
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:CLLocationCoordinate2DMake(52.00, 148.00)
coordinate:CLLocationCoordinate2DMake(18.00, -71.00)];
GMSPlacesClient * placesClient = [[GMSPlacesClient alloc] init];
[placesClient autocompleteQuery:fieldValue bounds:bounds filter:nil
callback:^(NSArray *results, NSError *error)
{
if (error != nil)
{
NSLog(#"Autocomplete error %#", [error localizedDescription]);
return;
}
else
{
[self.autoComplete removeAllObjects];
[self.AddressPlaceID removeAllObjects];
for (GMSAutocompletePrediction* result in results)
{
CustomAddress * parseAddress = [[CustomAddress alloc] init];
NSString * adString = [parseAddress removeCountryFromAddress:result.attributedFullText.string];
[self.autoComplete addObject:adString];
[self.AddressPlaceID addObject:result.placeID];
}
[self.autoCompleteTable reloadData];
}
}];
But you can still get the other location results . It will prefer first the geographical bounds you define in the GMCoordinateBounds
Why do not use the iOS SDK to obtain country specific results? Follow this answer.

Showing label next to MKPolyline [duplicate]

I'm using MapKit to display directions between locations, and I'm looking for a way to add an annotation that works similarly to the route annotation in the Apple Maps app, where annotations are showing each route's travel time (as shown in the image below). I am already drawing the directions correctly, the problem at hand is how to calculate a pair of coordinates along the route. That is, where to drop the annotation.
I thought about somehow using the MKDirection (which contains complete directions, step by step) but I am not sure how I would generate a pair of coordinates that are somewhere in the middle of the route.
I have not been able to find any kind of support for this in the MapKit documentation. Any ideas?
This is how I generate the route and display it.
- (void)generateRoute {
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
request.source = [MKMapItem mapItemForCurrentLocation];
request.destination = self.destinationMapItem;
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error) {
// Handle Error
} else {
[self showRoute:response];
}
}];
}
- (void)showRoute:(MKDirectionsResponse *)response {
[self.mapView removeOverlays:self.mapView.overlays];
for (MKRoute *route in response.routes)
{
[self.mapView addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
}
[self fitRegionToRoute];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id < MKOverlay >)overlay
{
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
renderer.strokeColor = [UIColor blueColor];
renderer.alpha = 0.7;
renderer.lineWidth = 4.0;
return renderer;
}
Questioner's edit:
Finally made it work with the help of this answer. I added this to the code below, where it says Here do the magic:
MKMapPoint middlePoint = route.polyline.points[route.polyline.pointCount/2];
[self createAndAddAnnotationForCoordinate:MKCoordinateForMapPoint(middlePoint)];
Original answer:
I don't know whether this will work or not. Just my idea on your question.
I guess you would have created the routes as following
(Check my inline comments)
MKDirectionsRequest *request =
[[MKDirectionsRequest alloc] init];
request.source = [MKMapItem mapItemForCurrentLocation];
request.destination = _destination;
request.requestsAlternateRoutes = NO;
MKDirections *directions =
[[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error) {
// Handle error
} else {
for (MKRoute *route in response.routes)
{
[_routeMap addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
//Here do the magic
//MKPolyline confronts to MKOverlay so you can get the coordinate like
//route.polyline.coordinate once you get the coordinate then you can build
//a annotation. A annotation is nothing but a coordinate with some title.
//According to MKOverlay coordinate property it justs gives you the
//center point of the overlay area
[self createAndAddAnnotationForCoordinate:route.polyline.coordinate]
}
}
}];
Adding Annotation
-(void) createAndAddAnnotationForCoordinate : (CLLocationCoordinate2D) coordinate{
MyAnnotation* annotation= [[MyAnnotation alloc] init];
annotation.coordinate = coordinate;
annotation.title = #"Any Title";
annotation.subtitle = #"Any Subtitle";
[yourMap addAnnotation: annotation];
}
If you want to know the middle for swift you can use the following code :
MKCoordinateForMapPoint(route.polyline.points()[route.polyline.pointCount/2])
Exemple of use :
directions.calculateDirectionsWithCompletionHandler ({
(response: MKDirectionsResponse?, error: NSError?) in
if error == nil {
self.showRoute(response!)
}
else{
print("some error")
}
})
func showRoute(response:MKDirectionsResponse){
for route in response.routes {
self.map.addOverlay(route.polyline, level: MKOverlayLevel.AboveRoads)
self.map.setCenterCoordinate(route.polyline.coordinate, animated: true)
self.map.setRegion(MKCoordinateRegionMakeWithDistance(route.polyline.coordinate, route.distance*0.75, route.distance*0.75), animated: true)
let routeAnnotation = MKPointAnnotation()
routeAnnotation.coordinate = MKCoordinateForMapPoint(route.polyline.points()[route.polyline.pointCount/2])
map.addAnnotation(routeAnnotation)
}
}
Perhaps not the most efficient way, but should still likely be quick, would be to calculate the midpoint of your start and end points (i.e., average their lats and longs). Then, iterate through your polyline points checking the distance from each to that midpoint. Take the closest match.
Even if the line is wildly curved, the midpoint will be directly between the ends. Some point on the wild curve is the closest to that external midpoint and is likely a good place to put the annotation.
Once you have an MKRoute, the approximate centre-point can be found using:
route.polyline.coordinate
This returns a CLLocationCoordinate2D that you can use to centre your annotation.
Appreciate this is an old question but I'd been searching for something like this for a while and ended up calculating the centre manually. Turns out it's very straightforward since iOS 8.
I suggest you see this , Integrated with routing.

Resources