I am working on one app, I need to show route directions between two coordinates. I have used MKDirections and have passed two coordinates as source and destination, however on mapView its not showing any route or drawing any polyline. Below is my code. In MKDirections its always showing nil. Please let me know what I am doing wrong.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.activityIndicator.hidden = YES;
self.routeDetailsButton.hidden = YES;
self.routeDetailsButton.enabled = NO;
self.mapView.delegate = self;
self.mapView.showsUserLocation = YES;
self.navigationItem.title = #"RouteMaster";
}
#pragma mark - MapKit delegate methods
- (void)mapView:(MKMapView *)aMapView didUpdateUserLocation:(MKUserLocation *)userLocation {
CLLocationCoordinate2D loc = [userLocation.location coordinate];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(loc, 1000.0f, 1000.0f);
[self.mapView setRegion:region animated:YES];
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (IBAction)handleRoutePressed:(id)sender {
// We're working
CLLocationCoordinate2D sourceCoords = CLLocationCoordinate2DMake(28.6100, 77.2300);
MKPlacemark *sourcePlacemark = [[MKPlacemark alloc] initWithCoordinate:sourceCoords addressDictionary:nil];
MKMapItem *srcMapItem = [[MKMapItem alloc]initWithPlacemark:sourcePlacemark];
CLLocationCoordinate2D destinationCoords = CLLocationCoordinate2DMake(18.9750, 72.8258);
MKPlacemark *destinationPlacemark = [[MKPlacemark alloc] initWithCoordinate:destinationCoords addressDictionary:nil];
MKMapItem *distMapItem = [[MKMapItem alloc]initWithPlacemark:destinationPlacemark];
MKDirectionsRequest *request = [[MKDirectionsRequest alloc]init];
[request setSource:srcMapItem];
[request setDestination:distMapItem];
MKDirections *direction = [[MKDirections alloc]initWithRequest:request];
[direction calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
if (error)
NSLog(#"Error %#", error.description);
else
NSLog(#"response = %#",response);
NSArray *arrRoutes = [response routes];
[arrRoutes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
MKRoute *rout = obj;
MKPolyline *line = [rout polyline];
[self.mapView addOverlay:line];
NSLog(#"Rout Name : %#",rout.name);
NSLog(#"Total Distance (in Meters) :%f",rout.distance);
NSArray *steps = [rout steps];
NSLog(#"Total Steps : %lu",(unsigned long)[steps count]);
[steps enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(#"Rout Instruction : %#",[obj instructions]);
NSLog(#"Rout Distance : %f",[obj distance]);
}];
}];
}];
}
#pragma mark - Utility Methods
- (void)plotRouteOnMap:(MKRoute *)route
{
if(_routeOverlay) {
[self.mapView removeOverlay:_routeOverlay];
}
// Update the ivar
_routeOverlay = route.polyline;
// Add it to the map
[self.mapView addOverlay:_routeOverlay];
}
#pragma mark - MKMapViewDelegate methods
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
renderer.strokeColor = [UIColor redColor];
renderer.lineWidth = 4.0;
return renderer;
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id)overlay {
if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolylineView* aView = [[MKPolylineView alloc]initWithPolyline:(MKPolyline*)overlay] ;
aView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.5];
aView.lineWidth = 10;
return aView;
}
return nil;
}
Mostly this error occur if [_mapView setRegion:region] area and polyline route path are not on same region(both should need to display on same screen).
In my case I was searching for USA route path while my region was India. So it wont call to -(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay; function.
add this method
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
MKPolylineRenderer * routeLineRenderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
routeLineRenderer.strokeColor = [UIColor blueColor];
routeLineRenderer.lineWidth = 4;
return routeLineRenderer;
}
Related
How to get location like google maps which shows exact paths between locations. As it shows direct straight line which does not contain any path between both places and neither shows location around them through which it passes.
I have used following code:
CLLocationCoordinate2D coordinateArray[2];
coordinateArray[0] = CLLocationCoordinate2DMake(51.5074, 0.1278);
coordinateArray[1] = CLLocationCoordinate2DMake(48.8566, 2.3522);
self.routeLine = [MKPolyline polylineWithCoordinates:coordinateArray count:2];
[self.mapView setVisibleMapRect:[self.routeLine boundingMapRect]]; //If you want the route to be visible
[self.mapView addOverlay:self.routeLine];
For connection of both the paths this code have been implemented.
-(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
if(overlay == self.routeLine)
{
if(nil == self.routeLineView)
{
self.routeLineView = [[MKPolylineView alloc] initWithPolyline:self.routeLine];
self.routeLineView.fillColor = [UIColor redColor];
self.routeLineView.strokeColor = [UIColor redColor];
self.routeLineView.lineWidth = 5;
}
return self.routeLineView;
}
return nil;
}
Try my code one:
- (void)drawRouteFromLocation:(LocationPin *)source toLocation:(LocationPin *)destination
{
[self removeCurrentRouteDrawing];
MKPlacemark *sourcePlaceMark = [[MKPlacemark alloc]initWithCoordinate:source.actualCoordinate addressDictionary:nil];
MKPlacemark *destinationPlaceMark = [[MKPlacemark alloc]initWithCoordinate:destination.actualCoordinate addressDictionary:nil];
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
request.source = [[MKMapItem alloc] initWithPlacemark:sourcePlaceMark];
request.destination = [[MKMapItem alloc] initWithPlacemark:destinationPlaceMark];
request.requestsAlternateRoutes = NO;
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error)
{
// Handle Error
}
else
{
[self showRoute:response];
}
}];
}
-(void)showRoute:(MKDirectionsResponse *)response
{
for (MKRoute *route in response.routes)
{
[self.mkMapView addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
// for (MKRouteStep *step in route.steps)
// {
// DEBUG_LOG(#"%#", step.instructions);
// }
}
}
#pragma mark - MKMapViewDelegate
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
{
// DEBUG_LOG(#"region Will Change");
if ([self.delegate respondsToSelector:#selector(mapView:regionWillChangeAnimated:)])
{
[self.delegate mapView:mapView regionWillChangeAnimated:animated];
}
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
// DEBUG_LOG(#"region Did Change");
if ([self.delegate respondsToSelector:#selector(mapView:regionDidChangeAnimated:)])
{
[self.delegate mapView:mapView regionDidChangeAnimated:animated];
}
}
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView
{
DEBUG_LOG(#"mapView Did Finish Loading Map");
self.mapInitialized = YES;
if ([self.delegate respondsToSelector:#selector(mapViewDidFinishLoadingMap:)])
{
[self.delegate mapViewDidFinishLoadingMap:mapView];
}
}
//- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
//{
// if ([overlay isKindOfClass: [MKPolyline class]])
// {
// // This is for a dummy overlay to work around a problem with overlays
// // not getting removed by the map view even though we asked for it to
// // be removed.
// MKOverlayView * dummyView = [[MKOverlayView alloc] init];
// dummyView.alpha = 0.0;
// return dummyView;
// }
// else
// {
// return nil;
// }
//}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([self.delegate respondsToSelector:#selector(mapView:viewForAnnotation:)])
{
return [self.delegate mapView:mapView viewForAnnotation:annotation];
}
return nil;
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id < MKOverlay >)overlay
{
if ([overlay isKindOfClass:[MKPolyline class]])
{
MKPolylineRenderer *renderer = [[ MKPolylineRenderer alloc]initWithOverlay:overlay];
renderer.lineWidth = 10;
renderer.strokeColor = [UIColor colorWithRed:0.0 green:122.0/255.0 blue:1.0 alpha:1.0];
[self _zoomToPolyLine:self.mkMapView polyLine:overlay animated:YES];
return renderer;
}
else
{
return nil;
}
}
#pragma mark - Utils
-(void)_zoomToPolyLine:(MKMapView*)map polyLine:(MKPolyline*)polyLine animated:(BOOL)animated
{
// MKPolygon* polygon =
// [MKPolygon polygonWithPoints:polyLine.points count:polyLine.pointCount];
//
// [self.mkMapView setRegion:MKCoordinateRegionForMapRect([polygon boundingMapRect])
// animated:animated];
[map setVisibleMapRect:[polyLine boundingMapRect] edgePadding:UIEdgeInsetsMake(35.0, 35.0, 35.0, 35.0) animated:animated];
}
- (void)removeCurrentRouteDrawing
{
if (self.mkMapView.overlays.count)
{
[self.mkMapView removeOverlays:self.mkMapView.overlays];
}
}
I plot the route between source and destination using the following piece of code. After plotting the route sucessfully, I get a list of coordinates where I wanted to plot another route on top of existing one with different color.
The use case I am trying to code is, we set source and destination, plot the dotted route once, then plot the actual line based on the list of locations
From the code, I can see the dotted line but can not see the another line overlapping on it.
My code is:
-(void) getDirection {
CLLocationCoordinate2D sourceCoords = CLLocationCoordinate2DMake(42.130655, -71.041158);
MKPlacemark *sourcePlacemark = [[MKPlacemark alloc] initWithCoordinate:sourceCoords addressDictionary:nil];
MKMapItem *source = [[MKMapItem alloc] initWithPlacemark:sourcePlacemark];
// Make the destination location
CLLocationCoordinate2D destinationCoords = CLLocationCoordinate2DMake(42.128121, -70.936151); MKPlacemark *destinationPlacemark = [[MKPlacemark alloc] initWithCoordinate:destinationCoords addressDictionary:nil];
MKMapItem *destination = [[MKMapItem alloc] initWithPlacemark:destinationPlacemark];
MKDirectionsRequest *directionsRequest = [MKDirectionsRequest new];
[directionsRequest setSource:source];
[directionsRequest setDestination:destination];
[self sourceMarker:sourcePlacemark];
[self destinationMarker:destinationPlacemark];
//
//routeCoords
NSInteger nuberOfStesps = routeCoords.count;
CLLocationCoordinate2D *pointsCoordinate = (CLLocationCoordinate2D *)malloc(sizeof(CLLocationCoordinate2D) * nuberOfStesps);
for (NSInteger index=0; index < nuberOfStesps; index++) {
CLLocation *location = [routeCoords objectAtIndex:index];
coordinate2 = location.coordinate;
//NSLog(#"Location Latitide : %f", coordinate2.latitude);
//NSLog(#"Location Longitude : %f", coordinate2.longitude);
pointsCoordinate[index] = CLLocationCoordinate2DMake(coordinate2.latitude, coordinate2.longitude);
}
routeLine = [MKPolyline polylineWithCoordinates:pointsCoordinate count:nuberOfStesps];
// free(pointsCoordinate);
routeLine.title = #"New points";
[self.mapView addOverlay:routeLine];
//
MKDirections *directions = [[MKDirections alloc] initWithRequest:directionsRequest];
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
if (error) {
NSLog(#"There was an error getting your directions");
return;
}else {
[self showRoute:response];
}
}];
}
- (void) showRoute:(MKDirectionsResponse * ) response {
_currentRoute = [response.routes firstObject];
[self.mapView setVisibleMapRect:_currentRoute.polyline.boundingMapRect animated:NO];
[self.mapView removeOverlays:self.mapView.overlays];
[self.mapView addOverlay:_currentRoute.polyline level:MKOverlayLevelAboveRoads];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
[renderer setStrokeColor:[UIColor redColor]];
[renderer setLineWidth:4.0];
[renderer setLineDashPattern:#[#2, #5]];
[renderer setStrokeColor:[UIColor redColor]];
return renderer;
}
return nil;
}
I followed this thread iOS Maps draw route (line) between several points (geopoints)
But it did not work for me. What am I doing wrong?
I want to show two location's distance in mapkit, I have tried my process its not showing the distance between the location. tried below codes its not working, can any one help me in coding.
MKMapView * mapView = [[MKMapView alloc]initWithFrame:CGRectMake(0, 294, 320, 122)];
mapView.showsUserLocation = YES;
mapView.delegate = self;
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
MKPlacemark *placemark1 = [[MKPlacemark alloc] initWithCoordinate:CLLocationCoordinate2DMake(9.9176458, 78.1228237) addressDictionary:nil];
[request setSource:[[MKMapItem alloc] initWithPlacemark:placemark1]];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:CLLocationCoordinate2DMake(13.0475604, 80.2089535) addressDictionary:nil];
request.destination = [[MKMapItem alloc] initWithPlacemark:placemark];
// [request setDestination:myMapItem];
[request setTransportType:MKDirectionsTransportTypeAutomobile]; // This can be limited to automobile and walking directions.
[request setRequestsAlternateRoutes:YES]; // Gives you several route options.
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
if (!error) {
for (MKRoute *route in [response routes]) {
[mapView addOverlay:[route polyline] level:MKOverlayLevelAboveRoads]; // Draws the route above roads, but below labels.
// You can also get turn-by-turn steps, distance, advisory notices, ETA, etc by accessing various route properties.
}
}
}];
[self.view addSubview:mapView];
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id < MKOverlay >)overlay
{
MKPolylineRenderer *renderer =
[[MKPolylineRenderer alloc] initWithOverlay:overlay];
renderer.strokeColor = [UIColor blueColor];
renderer.lineWidth = 5.0;
return renderer;
}
Please any help me .
If you check error in the -calculateDirectionsWithCompletionHandler:
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
if (!error) {
for (MKRoute *route in [response routes]) {
[mapView addOverlay:[route polyline] level:MKOverlayLevelAboveRoads]; // Draws the route above roads, but below labels.
// You can also get turn-by-turn steps, distance, advisory notices, ETA, etc by accessing various route properties.
}
}
else {
NSLog(#"%#", error);
}
}];
You will probably see
Error Domain=MKErrorDomain Code=5 "Directions Not Available" UserInfo=0x7fefe3bb5660 {NSLocalizedFailureReason=A route to the nearest road cannot be determined., MKErrorGEOError=-403, MKDirectionsErrorCode=6, NSLocalizedDescription=Directions Not Available}
Which means that it is not possible to calculate directions from given location.
Here is my code; I use CLLocationManager Delegate to compute distance between two location and MKMapView Delegate. here is my code, it may help you.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)location{
float distance = 0.0f;
NSMutableArray *locationArray = [[NSMutableArray alloc] init];
for (CLLocation *newLocation in location) {
[locationArray addObject:newLocation];
}
for (int i = 0 ; i < locationArray.count; i++) {
CLLocation *newLocation = [locationArray objectAtIndex:i];
distance += [newLocation distanceFromLocation:[locationArray objectAtIndex:i+1]];
}
NSLog(#"%f",distance);
CLLocationCoordinate2D cordinates [locationsArray.count];
MKPolyline *userLocationsPolyLine = [MKPolyline polylineWithCoordinates:cordinates count:locationsArray.count];
[userMapView setDelegate:self];
[userMapView addOverlay:userLocationsPolyLine];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
if ([overlay isKindOfClass:[MKPolyline class]]){
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
renderer.lineWidth = 3;
return renderer;
}
return nil;
}
I am trying get the coordinate of each pin I select on my map. Pins are the local search results that users search on the map. I have an issue that every pin I select it give me the same value. Can anyone help me with this please? Thanks in advance.
- (IBAction)searchAction:(id)sender {
[sender resignFirstResponder];
[self.mapView removeAnnotations:[self.mapView annotations]];
[self performSearch]; }
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKPinAnnotationView *mypin = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:#"current"];
//mypin.pinColor = MKPinAnnotationColorPurple;
mypin.backgroundColor = [UIColor clearColor];
UIButton *goToDetail = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
mypin.rightCalloutAccessoryView = goToDetail;
mypin.draggable = NO;
mypin.highlighted = YES;
mypin.animatesDrop = TRUE;
mypin.canShowCallout = YES;
return mypin;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
MKPointAnnotation *annotation = view.annotation;
self.tappedCoord = annotation.coordinate;
// Longs are the same for every pin I select
NSLog(#"%f", [[view annotation] coordinate].longitude);
}
- (void)performSearch {
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = _searchText.text;
request.region = _mapView.region;
self.matchingItems = [[NSMutableArray alloc] init];
MKLocalSearch *search = [[MKLocalSearch alloc]initWithRequest:request];
[search startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
if (response.mapItems.count == 0)
NSLog(#"No Matches");
else
for (MKMapItem *item in response.mapItems)
{
[self.matchingItems addObject:item];
MKPointAnnotation *annotation = [[MKPointAnnotation alloc]init];
annotation.coordinate = item.placemark.coordinate;
annotation.title = item.name;
annotation.subtitle = [NSString stringWithFormat:#"%#, %# %#",
item.placemark.addressDictionary[#"Street"],
item.placemark.addressDictionary[#"State"],
item.placemark.addressDictionary[#"ZIP"]];
//NSLog(#"%#", item.placemark.addressDictionary);
[_mapView addAnnotation:annotation];
}
}];
}
i want display a point to point route inside my mapView, i use this code for create the route:
- (IBAction)backToYourCar {
MKPlacemark *sourcePlacemark = [[MKPlacemark alloc] initWithCoordinate:self.annotationForCar.coordinate addressDictionary:nil];
NSLog(#"coordiante : locationIniziale %f", sourcePlacemark.coordinate.latitude);
MKMapItem *carPosition = [[MKMapItem alloc] initWithPlacemark:sourcePlacemark];
MKMapItem *actualPosition = [MKMapItem mapItemForCurrentLocation];
NSLog(#"coordiante : source %f, ActualPosition %f", carPosition.placemark.coordinate.latitude ,actualPosition.placemark.coordinate.latitude);
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
request.source = actualPosition;
request.destination = carPosition;
request.requestsAlternateRoutes = YES;
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
if (error) {
NSLog(#"Error : %#", error);
}
else {
[self showDirections:response]; //response is provided by the CompletionHandler
}
}];
}
and this for show the route on the map:
- (void)showDirections:(MKDirectionsResponse *)response
{
for (MKRoute *route in response.routes) {
[self.mapView addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
}
}
actually this code does nothing.
if i try to print the the distance of route i get the correct value:
route distance: 1910.000000
then the route is right, but i can't understand why it doesn't appear on the map!
Any suggestions?
after a day of research i have solved with this 3 steps:
Set the delegate (self.mapView.delegate = self).
import the MKMapViewDelegate
Implemente the new iOS7 MapView delegate method:
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay(id<MKOverlay>)overlay:
this is my implementation:
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolyline *route = overlay;
MKPolylineRenderer *routeRenderer = [[MKPolylineRenderer alloc] initWithPolyline:route];
routeRenderer.strokeColor = [UIColor blueColor];
return routeRenderer;
}
else return nil;
}
this method is automatically called by the delegate when you add the polyline on the map.