show route map between two address points - ios

I am working for door delivery app, here I am trying to show route map between pickup and dropping points. I've tried with the below code but showing straight line instead of a path.
CLLocationCoordinate2D coordinateArray[2];
coordinateArray[0] = CLLocationCoordinate2DMake(17.4368, 78.4439);
coordinateArray[1] = CLLocationCoordinate2DMake(16.5083, 80.6417);
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];
-(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 blackColor];
self.routeLineView.lineWidth = 5;
}
return self.routeLineView;
}
return nil;
}

You must use MKRoute and MKDirections for routing on roads.
Check out this documentation.
Good luck.

You can check with the MKDirectionRequest for routing direction.
Check out this link.

Related

Why This Code Does Not Draw Polyline on MKMapView

I have the following code, with which i am trying to draw a polyline between a set of coordinates (which are correct as I also use them to add pins to the map, and those work fine).
I call a drawing method to initiate the drawing like so (the array in the method call contains the necessary coordinates):
[self drawRoute:[[transportData objectForKey:#"19"] objectForKey:#"stops"]];
This is the actual method that is supposed to draw the line on the map (selectedRoute is an MKPolyline object):
- (void)drawRoute:(NSArray *)routePointsArray {
if (selectedRoute) {
[mapView removeOverlay:selectedRoute];
selectedRoute = nil;
}
CLLocationCoordinate2D routeCoordinates[routePointsArray.count];
for (int i = 0; i < routePointsArray.count; i++) {
float latitude = [[[routePointsArray objectAtIndex:i] objectForKey:#"lat"] floatValue];
float longitude = [[[routePointsArray objectAtIndex:i] objectForKey:#"lon"] floatValue];
CLLocationCoordinate2D routePoint = CLLocationCoordinate2DMake(latitude, longitude);
routeCoordinates[i] = routePoint;
}
selectedRoute = [MKPolyline polylineWithCoordinates:routeCoordinates count:routePointsArray.count];
[mapView addOverlay:selectedRoute];
[mapView setVisibleMapRect:[selectedRoute boundingMapRect]];
}
And this is my delegate:
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
MKPolylineRenderer *routeLineView = [[MKPolylineRenderer alloc] initWithPolyline:selectedRoute];
if(overlay == selectedRoute)
{
if(nil == routeLineView)
{
routeLineView = [[MKPolylineRenderer alloc] initWithPolyline:selectedRoute];
routeLineView.fillColor = [UIColor redColor];
routeLineView.strokeColor = [UIColor redColor];
routeLineView.lineWidth = 5;
}
return routeLineView;
}
return nil;
}
I kind of narrowed it down to the routeCoordinates array not getting filled up with coordinates, but I do not understand why.
Also, if you spot any mistakes in the code I would really appreciate if you could point those out to me (possibly with a solution) as I am just learning this part of iOS and can use any help I can get.
You have an error in your rendererForOverlay method.
The first thing it does is assign an instance of MKPolylineRenderer to routeLineView, but later you only actually add the overlay if routeLineView is nil, which it won't be.
Remove the line that assigns the initial value to routeLineView.

Prevent MKPolygon to have knots

I'm developing an app with a map in which the user can draw a polygon area.
My issue is what it's possible drawing polygons with knots (see the image) (I don't know if knot is the right word). I didn't find a simply way preventing the polygon to get knots.
For the case of the attached image, I would like the small curl to be removed and even the outline to be smoothed
Do you know a way to make that?
The process of drawing the polygon while the user is touching the screen, does use MKPolyline, MKPolygon and MKOverlay as follows:
- (void)touchesBegan:(UITouch*)touch
{
CGPoint location = [touch locationInView:self.mapView];
CLLocationCoordinate2D coordinate = [self.mapView convertPoint:location toCoordinateFromView:self.mapView];
[self.coordinates addObject:[NSValue valueWithMKCoordinate:coordinate]];
}
- (void)touchesMoved:(UITouch*)touch
{
CGPoint location = [touch locationInView:self.mapView];
CLLocationCoordinate2D coordinate = [self.mapView convertPoint:location toCoordinateFromView:self.mapView];
[self.coordinates addObject:[NSValue valueWithMKCoordinate:coordinate]];
}
- (void)touchesEnded:(UITouch*)touch
{
CGPoint location = [touch locationInView:self.mapView];
CLLocationCoordinate2D coordinate = [self.mapView convertPoint:location toCoordinateFromView:self.mapView];
[self.coordinates addObject:[NSValue valueWithMKCoordinate:coordinate]];
[self didTouchUpInsideDrawButton:nil];
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MKOverlayPathView *overlayPathView;
if ([overlay isKindOfClass:[MKPolygon class]])
{
// create a polygonView using polygon_overlay object
overlayPathView = [[MKPolygonView alloc] initWithPolygon:overlay];
overlayPathView.fillColor = [UIColor redColor];
overlayPathView.lineWidth = 1.5;
return overlayPathView;
}
else if ([overlay isKindOfClass:[MKPolyline class]])
{
overlayPathView = [[MKPolylineView alloc] initWithPolyline:(MKPolyline *)overlay];
overlayPathView.fillColor = [UIColor redColor];
overlayPathView.lineWidth = 3;
return overlayPathView;
}
return nil;
}
MKOverlayPathView was deprecated since iOS 7.0. You'd use MKOverlayRenderer instead of it and also related map delegate method.
Try to play with miterLimit property of MKOverlayRenderer.
Example:
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
if ([overlay isKindOfClass:[MKPolygon class]]) {
MKPolygonRenderer *polygonRenederer = [[MKPolygonRenderer alloc] initWithPolygon:overlay];
polygonRenederer.fillColor = [UIColor redColor];
polygonRenederer.lineWidth = 1.5;
polygonRenederer.miterLimit = 10;
return polygonRenederer;
} else if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolylineRenderer *lineRenderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
lineRenderer.strokeColor = [UIColor redColor];
lineRenderer.lineWidth = 3;
return lineRenderer;
}
return nil;
}

Mapbox iOS - Fill polygon created dynamically

I am using Mapbox framework for maps and i want to fill polygons and the vertices of the polygon has given from the user touch.
Here is my code on user touch
- (void)singleTapOnMap:(RMMapView *)map at:(CGPoint)point
{
CLLocationCoordinate2D coord;
coord.latitude = [map pixelToCoordinate:point].latitude;
coord.longitude = [map pixelToCoordinate:point].longitude;
RMAnnotation *annotation = [[RMAnnotation alloc] initWithMapView:map coordinate:coord andTitle:#""];
annotation.userInfo = [[NSArray alloc]initWithObjects:[[CLLocation alloc] initWithLatitude:coord.latitude longitude:coord.longitude], nil];
[map addAnnotation:annotation];
}
Delegate method
- (RMMapLayer *)mapView:(RMMapView *)mapView layerForAnnotation:(RMAnnotation *)annotation
{
if (annotation.isUserLocationAnnotation)
return nil;
CLLocation *location = [annotation.userInfo objectAtIndex:0];
RMShape *line = [[RMShape alloc] initWithView:annotation.mapView];
line.lineWidth = 3.0;
line.position = annotation.position;
line.lineColor = [UIColor redColor];
line.fillColor = [UIColor greenColor];
[line moveToCoordinate:location.coordinate];
[line addLineToCoordinate:lastLocation.coordinate];
return line;
}
I can draw the polygon but unable to fill it.
It seems to me that, according to the way that you are currently doing it, for each tap on the map you are creating a NEW annotation, each containing one line segment from the last location to the current tap location, which will not create a polygon, but rather a series of individual annotations containing only one line segment.
You will need to create a separate array of locations of vertices. As you add more locations via tapping it adds to the location array:
// #1 create the following iVars for keeping state of drawing and polygon vertices
bool isDrawingPolygon;
NSMutableArray *savedPolygonVertices;
// #2 in viewDidLoad or your init code, be sure to set the initial states
-(void)viewDidLoad
{
isDrawingPolygon = FALSE;
savedPolygonVertices = nil;
...
... REST OF VIEW DID LOAD OR INIT METHOD
// #3 Create an IBAction button method to trigger beginning of drawing dynamic polygon (a start button)
-(void)startCreatingPolygon
{
isDrawingPolygon = TRUE;
savedPolygonVertices = [[NSMutableArray alloc] initWithCapacity:50]; // Some arbitrary number of points
}
// #4 Begin adding location vertices whenever singleTapOnMap
-(void)singleTapOnMap:(RMMapView *)map at:(CGPoint)point
{
if (isDrawingPolygon)
{
CLLocationCoordinate2D coord;
coord.latitude = [map pixelToCoordinate:point].latitude;
coord.longitude = [map pixelToCoordinate:point].longitude;
[savedPolygonVertices addObject:coord];
RMAnnotation *annotation = [[RMAnnotation alloc] initWithMapView:map coordinate:coord andTitle:#"tempPolygon"]; // Give each temporary line annotation some common identifier "tempPolygon"
annotation.userInfo = [[NSArray alloc]initWithObjects:[[CLLocation alloc] initWithLatitude:coord.latitude longitude:coord.longitude], nil];
[map addAnnotation:annotation];
}
}
// #5 When you tap the "stop" button, you would need to roll the location vertices in the array into ONE annotation object containing an RMShape polygon containing all the vertices for the polygon (and fill/line color attributes), and an identifier for that polygon.
-(void)stopCreatingPolygon // IBAction method for stop making polygon
{
isDrawingPolygon = FALSE;
RMAnnotation *annotation = [[RMAnnotation alloc] initWithMapView:self.mapView coordinate:coord andTitle:#"Polygon"];
annotation.userInfo = savedPolygonVertices;
[self.mapView addAnnotation:annotation];
savedPolygonVertices = nil;
for (RMAnnotation *ann in self.mapView.annotations)
{
if ([ann.title isEqualToString:#"tempPolygon"])
[self.mapView removeAnnotation:ann]; // Get rid of the temporary line segments
}
}
// #6 Then in layerForAnnotation, you would need to check for that identifier (annotation.title), and put the polygon wrapped in an if statement
- (RMMapLayer *)mapView:(RMMapView *)mapView layerForAnnotation:(RMAnnotation *)annotation
{
if (annotation.isUserLocationAnnotation)
return nil;
if ([annotation.title isEqualToString:#"tempPolygon"])
{
CLLocation *location = [annotation.userInfo objectAtIndex:0];
RMShape *line = [[RMShape alloc] initWithView:annotation.mapView];
line.lineWidth = 3.0;
line.position = annotation.position;
line.lineColor = [UIColor redColor];
line.fillColor = [UIColor greenColor];
[line moveToCoordinate:location.coordinate];
[line addLineToCoordinate:lastLocation.coordinate];
return line;
}
if ([annotation.title isEqualToString:#"Polygon"])
{
RMShape *shape = [[RMShape alloc] initWithView:self.mapView];
shape.lineWidth = 3.0;
shape.lineColor = [UIColor redColor];
shape.fillColor = [UIColor greenColor];
shape.fillRule= kCAFillRuleNonZero;
shape.lineJoin = kCALineJoinRound;
shape.lineCap = kCALineCapRound;
for (CLLocationCoordinate2D * location in annotation.userInfo){
// userInfo now contains all vertices between start & stop
[shape addLineToCoordinate:location];
}
return shape;
}
}
That should give you what you are looking for.
/blee/

How to use MKRoute to create specific path?

I'm relatively new to the iOs scenario, so this may be a dumb question but anyways...
I've been working on a project, and I wanted to do a specific route highlighted on the map. For exemple: A bus's itinerary is always the same, so I'd like to highlight the streets that the bus goes through before reaching his final destination.
The thing is I was only able to get directions from one point to another, but it does not follow the bus's itinerary, so it does not work for me.
Please help!!
First if you require specific route you will need some of its coordinates. Let's say you have some route coordinates as NSDictionary objects like in the example below
{
Lat = 53.3478;
Lon = -6.2597;
}
Stored in NSArray called routeLocations then you can do the following:
CLLocationCoordinate2D routeCoord[routeLocations.count];
for (int i = 0; i < routeLocations.count; i++ )
{
id location =[routeLocations objectAtIndex:i];
routeCoord[i] = CLLocationCoordine2DMake([[location objectForKey:#"Lat"]floatValue], [[location objectForKey:#"Lon"]floatValue]);
}
// create your route Polyline
MKPolyline *poly = [MKPolyline polylineWithCoordinates:routeCoord count:routeLocations.count];
// first remove previously added overlays if any then add your newly created route polyline
[self.mapView addOverlay:poly];
If you require customization on your overlay you can implement the following
For iOS >= 7
-(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 use deprecated method
-(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
if ([overlay isKindOfClass:[MKPolyline class]])
{
MKPolylineView *route = [[MKPolylineView alloc]initWithPolyline:overlay];
route.strokeColor = [UIColor blueColor];
return route;
}
}

how to set a mapRect for mkOverlay?

i want set a rect on top of the polyline route on my map.
this is what exactly i'm trying to do:
- (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] colorWithAlphaComponent:0.7];
routeRenderer.lineWidth = 5.0;
[self.mapView.visibleMapRect = route.boundingMapRect];
return routeRenderer;
}
else return nil;
}
i have problem with this line of code :
[self.mapView.visibleMapRect = route.boundingMapRect];
i get the "Expected identifier" error. what is wrong with this line of code?
is that the correct way to set an Mkrect for an MKPolyline route?
thanks!
That's not how you write objective-C, try this
self.mapView.visibleMapRect = route.boundingMapRect;
or
[self.mapView setVisibleMapRect:route.boundingMapRect animated:YES];
i have solved with this tow line of code:
MKMapRect test = MKMapRectInset(route.boundingMapRect, -route.boundingMapRect.size.height/2, -route.boundingMapRect.size.width/2);
[self.mapView setVisibleMapRect:test animated:YES];

Resources