I am developing an iOS app where I have to get directions from one location to another. I am getting the directions using the MKDirectionsRequest API. This api gives direction between two locations. But the problem is that the route returned by this api do not consider the direction (course) in which the vehicle is moving. Is there any way to get route between user current location to the destination in iOS which also takes the course of the moving vehicle into consideration. Currently I am using the following function:
-(void)displayDirections{
CLLocation *currentLocation = [[CLLocation alloc] initWithLatitude:currentLocationLatitude longitude:currentLocationLongitude];
MKPlacemark *placemarker0 = [[MKPlacemark alloc]initWithCoordinate:currentLocation.coordinate];
MKMapItem *myMapItem0 = [[MKMapItem alloc] initWithPlacemark:placemarker0];
CLLocation *location = [[CLLocation alloc] initWithLatitude:destinationLocationLatitude longitude:destinationLocationLongitude]
MKPlacemark *placemarker1 = [[MKPlacemark alloc]initWithCoordinate:location.coordinate];
MKMapItem *myMapItem1 = [[MKMapItem alloc] initWithPlacemark:placemarker1];
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
[request setSource:myMapItem0];
[request setDestination:myMapItem1];
[request setTransportType:MKDirectionsTransportTypeAny];
[request setRequestsAlternateRoutes:YES]; // Gives you several route options.
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
__weak COMSiteDetailViewController *weakSelf = self;
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
if (!error) {
[weakSelf.mkMapView removeOverlays:weakSelf.mkMapView.overlays];
NSArray *routes = [response routes];
NSArray *sortedArray;
sortedArray = [routes sortedArrayUsingComparator:^NSComparisonResult(MKRoute *a, MKRoute *b) {
CLLocationDistance first = a.distance;
CLLocationDistance second = b.distance;
return first < second;
}];
int count = 1;
for (MKRoute *route in sortedArray) {
if(count < sortedArray.count){
route.polyline.title = #"longer";
}else{
route.polyline.title = #"shortest";
}
count++;
[self.mkMapView addOverlay:[route polyline] level:MKOverlayLevelAboveRoads];
}
}
}];
}
Thanks in advance!
After searching the web I have found that neither Google API or Apple MapKit Directions API consider the heading or movement of the vehicle while giving the route information. It just consider the coordinates of the start/end locations and give the shortest route(s).
So there is no way, at the moment, to display route considering vehicle heading using Apple/Google Apis.
Although, there are other paid Apis such as https://developer.here.com which I used in my app. This api is very reliable and the pricing too is very reasonable.
Thanks!
I'm having a bug with the convertion of an NSString (which contains a place from a UITextField input) to a CLLocation.
Here is the method supposed to process the convertion:
- (void)geoCodeForAddress:(NSString *)address {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:address completionHandler:^(NSArray* placemarks, NSError* error){
dispatch_async(dispatch_get_main_queue(), ^{
CLPlacemark *placeMark = [placemarks lastObject];
if (placeMark.location != nil) {
self.actionLocation = placeMark.location;
} else {
self.actionLocation = nil;
}
if(self.event)
[self.tableView reloadData];
});
}];
}
My problem is, this method returns the wrong location for some specific strings. For instance, whenever I try to use "la patache paris" as an input, it returns a location in the wrong city though when I try the same exact string in Maps, it's finding the right place.
The method geocodeAddressString:completionHandler: is a CoreLocation method from the CLGeocoder class so there is no way I can see what's going on in it.
Would someone have some lead to find out why this is behaving weirdly ?
Thank you.
I'm searching for places (would like to only show businesses if possible) like this:
CLLocationCoordinate2D currentCenter = CLLocationCoordinate2DMake(self.locationManager.location.coordinate.latitude, self.locationManager.location.coordinate.longitude);
MKCoordinateRegion currentRegion = MKCoordinateRegionMakeWithDistance(currentCenter, 15000, 15000);
MKLocalSearchRequest *localSearchRequest = [[MKLocalSearchRequest alloc] init];
localSearchRequest.naturalLanguageQuery = identifier;
[localSearchRequest setRegion:currentRegion];
MKLocalSearch *localSearch = [[MKLocalSearch alloc] initWithRequest:localSearchRequest];
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *respone, NSError *error) {
if (!error)
{
// Result handling
}
}];
but the results include results from other countries, why is this? I only call this method if the CLLocationManager coordinate passes this check:
CLLocationCoordinate2DIsValid
Thanks!
I have an array of locations and when I add another I want to be able to check if the other locations in the array are within a block of the new one. This is the Code I have to find the current location:
//Geocoding Block
[self.geoCoder reverseGeocodeLocation: locationManager.location completionHandler:
^(NSArray *placemarks, NSError *error) {
//Get nearby address
CLPlacemark *placemark = [placemarks objectAtIndex:0];
//String to hold address
locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
The array has yet to be created because I want to figure this out first, I dont know what should be held in the array (string...). I know how to do a search I just need to know how to compare the locations.
You can get the distance between two locations using the distanceFromLocation: method on CLLocation. (You can get a CLLocation out of a CLPlacemark with myPlacemark.location.) So if you have an array of CLLocation objects, and you want to find the ones that are within one block (1/20 mile, or about 80 meters), you can do this:
NSMutableArray *locationsWithinOneBlock = [NSMutableArray new];
for (CLLocation *location in myLocations) {
if ([location distanceFromLocation:targetLocation] <= 80.0)
[locationsWithinOneBlock addObject:location];
}
This assumes you have an array myLocations of CLLocation objects that you want to filter against a single CLLocation called targetLocation.
I want to use MKLocalSearch for searching in a Map. This functionality is available in iOS 6.1+. Does anybody know how to use this or can anybody give an example of how to use an MKLocalSearch?
MKLocalSearchResponse documentation
The API for MKLocalSearch is fairly easy to understand. At its most basic, you
alloc-init an MKLocalSearchRequest
Set its naturalLanguageQuery to some search term
Use the search request to initialize an MKLocalSearch object
Tell the local search to start, passing it a completion handler
Do something with the array of MKMapItem objects in the response
Search for Cafes:
// Create a search request with a string
MKLocalSearchRequest *searchRequest = [[MKLocalSearchRequest alloc] init];
[searchRequest setNaturalLanguageQuery:#"Cafe"];
// Create the local search to perform the search
MKLocalSearch *localSearch = [[MKLocalSearch alloc] initWithRequest:searchRequest];
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
if (!error) {
for (MKMapItem *mapItem in [response mapItems]) {
NSLog(#"Name: %#, Placemark title: %#", [mapItem name], [[mapItem placemark] title]);
}
} else {
NSLog(#"Search Request Error: %#", [error localizedDescription]);
}
}];
You can specify a region for the search like this:
// Search for Cafes in Paris
MKLocalSearchRequest *searchRequest = [[MKLocalSearchRequest alloc] init];
[searchRequest setNaturalLanguageQuery:#"Cafe"];
CLLocationCoordinate2D parisCenter = CLLocationCoordinate2DMake(48.8566667, 2.3509871);
MKCoordinateRegion parisRegion = MKCoordinateRegionMakeWithDistance(parisCenter, 15000, 15000);
[searchRequest setRegion:parisRegion];
You can also take the region from an MKMapView that the user has zoomed into. This will give better results:
[searchRequest setRegion:self.mapView.region];
The response object, an MKLocalSearchResponse, contains an array of MKMapItem objects (mapItems) and an MKCoordinateRegion called boundingRegion, which is a region that contains all the results. You can use it to set a map view to show all results:
[self.mapView setRegion:response.boundingRegion];
The array of MKMapItem objects can't be placed on a map (they're used for sending to the Maps app) but each contains a placemark property which can be added to a map:
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
if (!error) {
for (MKMapItem *mapItem in [response mapItems]) {
NSLog(#"Name: %#, MKAnnotation title: %#", [mapItem name], [[mapItem placemark] title]);
NSLog(#"Coordinate: %f %f", [[mapItem placemark] coordinate].latitude, [[mapItem placemark] coordinate].longitude);
// Should use a weak copy of self
[self.mapView addAnnotation:[mapItem placemark]];
}
} else {
NSLog(#"Search Request Error: %#", [error localizedDescription]);
}
}];
Search for Dublin places a pin on the map view and logs:
Name: Dublin, Co. Dublin, MKAnnotation title: Dublin, Co. Dublin, Ireland
Coordinate: 53.344104 -6.267494
There are a load of extra details in the returned objects, especially if you search for businesses. Here are a few:
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
if (!error) {
NSLog(#"Results: %#", [response mapItems]);
MKMapItem *mapItem = [[response mapItems] objectAtIndex:0];
NSLog(#"Name:%# Phone:%# URL:%#", [mapItem name], [mapItem phoneNumber], [mapItem url]);
NSLog(#"Placemark: %#", [mapItem placemark]);
MKPlacemark *placemark = [mapItem placemark];
NSLog(#"Placemark Address: %#", [placemark addressDictionary]);
MKCoordinateRegion boundingRegion = [response boundingRegion];
NSLog(#"Bounds: %f %f", boundingRegion.span.latitudeDelta, boundingRegion.span.longitudeDelta);
}
Here is an example that search for cafes in a radius of 1 km around a given location :
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
CLLocationCoordinate2D location = CLLocationCoordinate2DMake(11.567898, 104.894430);
request.naturalLanguageQuery = #"cafe";
request.region = MKCoordinateRegionMakeWithDistance(location, 1000, 1000);
MKLocalSearch *search = [[MKLocalSearch alloc] initWithRequest:request];
[search startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error){
for (MKMapItem *item in response.mapItems) {
NSLog(#"%#", item.name);
}
}];
Please note than when the search is unsuccessful, it does not return an empty list, but an error with domain MKErrorDomain and code 4.
Here is a tutorial for Localsearch
http://jeffreysambells.com/2013/01/28/mklocalsearch-example