Drawing route partially not getting required output in iPhone MapView - iphone

I am trying to draw route between two points using polyline . I got somewhat route but not correct and I think it will get confused at the turn . I am using google api for getting points of route .Following is code what i tried please check .
- (IBAction)onclickDrawButton:(id)sender
{
flag=TRUE;
NSString *startpoint=[satrtTextfield text];
NSString *endpoint=[endTextfield text];
NSMutableString *urlString=[NSMutableString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=%#&destination=%#&sensor=false",startpoint,endpoint];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
if(connection)
{
NSLog(#"connectin done");
}
}
-(void)connection:(NSURLConnection*)connection didReceiveResponse: (NSURLResponse*)response
{
if(flag)
{
recievedRoutes=[[NSMutableData alloc]init];
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if(flag){
NSString *jsonResult = [[NSString alloc] initWithData:recievedRoutes encoding:NSUTF8StringEncoding];
NSLog(#"json response %#",jsonResult);
NSDictionary *partialJsonDict=[jsonResult JSONValue];
NSArray *items=[partialJsonDict valueForKey:#"routes"];
//NSLog(#"responsed valued %#",[[items objectAtIndex:0]valueForKey:#"legs"]);
NSArray *aary=[[items objectAtIndex:0]valueForKey:#"legs"];
NSLog(#"legs array wuth polyline %#",[[aary objectAtIndex:0]valueForKey:#"steps"]);
NSArray *steps=[[aary objectAtIndex:0]valueForKey:#"steps"];
NSLog(#"steps %#",[[steps objectAtIndex:1]objectForKey:#"polyline"]);
NSMutableString *string=[[NSMutableString alloc]init];
for(int i=0;i<[steps count];i++)
{
//NSLog(#"steps i value %#",[[[steps objectAtIndex:i]objectForKey:#"polyline"]objectForKey:#"sttpoints"]);
[string appendString:[[[steps objectAtIndex:i]objectForKey:#"polyline"]objectForKey:#"points"]];
}
NSLog(#"final %#",string);
MKPolyline *polyline=[self polylineWithEncodedString:string];
[mapView addOverlay:polyline];
[self zoomToFitMapAnnotations:mapView];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if(flag){
[recievedRoutes appendData:data];
}
}
//to decode polyline and retrives coordintes i have used following method
-(MKPolyline *)polylineWithEncodedString:(NSString *)encodedString {
const char *bytes = [encodedString UTF8String];
NSUInteger length = [encodedString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSUInteger idx = 0;
NSUInteger count = length / 4;
CLLocationCoordinate2D *coords = calloc(count, sizeof(CLLocationCoordinate2D));
NSUInteger coordIdx = 0;
float latitude = 0;
float longitude = 0;
while (idx < length) {
char byte = 0;
int res = 0;
char shift = 0;
do {
byte = bytes[idx++] - 63;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1));
latitude += deltaLat;
shift = 0;
res = 0;
do {
byte = bytes[idx++] - 0x3F;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1));
longitude += deltaLon;
float finalLat = latitude * 1E-5;
float finalLon = longitude * 1E-5;
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(finalLat, finalLon);
coords[coordIdx++] = coord;
NSLog(#"in encoding %f %f ",latitude,longitude);
if (coordIdx == count) {
NSUInteger newCount = count + 10;
coords = realloc(coords, newCount * sizeof(CLLocationCoordinate2D));
count = newCount;
}
}
MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords count:coordIdx];
free(coords);
return polyline;
}
// to draw actual route
- (MKOverlayView *)mapView:(MKMapView *)mapView
viewForOverlay:(id<MKOverlay>)overlay {
MKPolylineView *overlayView = [[MKPolylineView alloc] initWithOverlay:overlay];
overlayView.lineWidth = 2;
overlayView.strokeColor = [UIColor purpleColor];
overlayView.fillColor = [[UIColor purpleColor] colorWithAlphaComponent:0.1f];
return overlayView;
}

After your line
NSArray *steps=[[aary objectAtIndex:0]valueForKey:#"steps"];
replace lines with this may work
NSMutableArray *polyLinesArray = [[NSMutableArray alloc] init];
for (int i = 0; i < [steps count]; i++)
{
NSString* encodedPoints = [[[steps objectAtIndex:i] objectForKey:#"polyline"] valueForKey:#"points"];
MKPolyline *route = [self polylineWithEncodedString:encodedPoints];
[polyLinesArray addObject:route];
}
[self.mapView addOverlays:polyLinesArray];
[polyLinesArray release];

Related

Drawing a route on Apple map (iOS 6+)

I was looking for many code samples of how to draw a polyline on MKMapView like the second answer (from above) in this link. However, will that solution work on iOS 6 Apple maps? If not, can you provide a link to a sample code that draws the route on Apple maps?
Yes, it'll work.
Google maps and apple maps are different a little bit, could be some little inaccuracies.
All the API's are almost same.
P.S. I use google routes in my app since iOS5 and haven't got any problems when updated app for iOS6.
-(void)load_mapView{
Place* home = [[[Place alloc] init] autorelease];
home.name = strAdd;
CLLocationCoordinate2D loc=[self geoCodeUsingAddress:strAdd Status:1];
home.latitude =loc.latitude;
home.longitude =loc.longitude;
Place* office = [[[Place alloc] init] autorelease];
office.name = endAdd;
CLLocationCoordinate2D loc2=[self geoCodeUsingAddress:endAdd Status:2];;
office.latitude = loc2.latitude;
office.longitude = loc2.longitude;
//*******
routeView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, mapView.frame.size.width, mapView.frame.size.height)];
routeView.userInteractionEnabled = NO;
[mapView addSubview:routeView];
lineColor = [UIColor colorWithWhite:0.2 alpha:0.5];
[self showRouteFrom:home to:office];
[activityIndicator stopAnimating];
}
- (CLLocationCoordinate2D) geoCodeUsingAddress:(NSString *)address Status:(NSInteger )sts
{
double latitude = 0, longitude = 0;
NSString *esc_addr = [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *req = [NSString stringWithFormat:#"http://maps.google.com/maps/api/geocode/json?sensor=false&address=%#", esc_addr];
NSString *result = [NSString stringWithContentsOfURL:[NSURL URLWithString:req] encoding:NSUTF8StringEncoding error:NULL];
if (result) {
NSScanner *scanner = [NSScanner scannerWithString:result];
if ([scanner scanUpToString:#"\"lat\" :" intoString:nil] && [scanner scanString:#"\"lat\" :" intoString:nil]) {
[scanner scanDouble:&latitude];
if ([scanner scanUpToString:#"\"lng\" :" intoString:nil] && [scanner scanString:#"\"lng\" :" intoString:nil]) {
[scanner scanDouble:&longitude];
}
}
}
CLLocationCoordinate2D center;
center.latitude = latitude;
center.longitude = longitude;
return center;
}
-(NSMutableArray *)decodePolyLine: (NSMutableString *)encoded {
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\"
options:NSLiteralSearch
range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[[NSNumber alloc] initWithFloat:lat * 1e-5] autorelease];
NSNumber *longitude = [[[NSNumber alloc] initWithFloat:lng * 1e-5] autorelease];
// printf("[%f,", [latitude doubleValue]);
// printf("%f]", [longitude doubleValue]);
CLLocation *loc = [[[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]] autorelease];
[array addObject:loc];
}
return array;
}
-(NSArray*) calculateRoutesFrom:(CLLocationCoordinate2D) f to: (CLLocationCoordinate2D) t {
NSString* saddr = [NSString stringWithFormat:#"%f,%f", f.latitude, f.longitude];
NSString* daddr = [NSString stringWithFormat:#"%f,%f", t.latitude, t.longitude];
Reachability *reachability = [Reachability reachabilityForInternetConnection];
NetworkStatus internetStatus = [reachability currentReachabilityStatus];
if (internetStatus != NotReachable){
NSString* apiUrlStr = [NSString stringWithFormat:#"http://maps.google.com/maps?output=dragdir&saddr=%#&daddr=%#", saddr, daddr];
NSURL* apiUrl = [NSURL URLWithString:apiUrlStr];
// NSLog(#"api url: %#", apiUrl);
NSString *apiResponse = [NSString stringWithContentsOfURL:apiUrl];
NSString* encodedPoints = [apiResponse stringByMatching:#"points:\\\"([^\\\"]*)\\\"" capture:1L];
// NSLog(#"encodedPoints.....%#",encodedPoints);
// NSLog(#"self decodePolyLine:[encodedPoints mutableCopy].....%#",[self decodePolyLine:[encodedPoints mutableCopy]]);
NSLog(#"return %# ",[encodedPoints mutableCopy]);
return [self decodePolyLine:[encodedPoints mutableCopy]];
}else{
[activityIndicator stopAnimating];
UIAlertView *alert =[[UIAlertView alloc]initWithTitle:#"Oops!" message:#"Railway server is either busy or not responding at the moment. Try again later." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
return 0;
}
}
-(void) centerMap {
MKCoordinateRegion region;
CLLocationDegrees maxLat = -90;
CLLocationDegrees maxLon = -180;
CLLocationDegrees minLat = 90;
CLLocationDegrees minLon = 180;
for(int idx = 0; idx < routes.count; idx++)
{
CLLocation* currentLocation = [routes objectAtIndex:idx];
if(currentLocation.coordinate.latitude > maxLat)
maxLat = currentLocation.coordinate.latitude;
if(currentLocation.coordinate.latitude < minLat)
minLat = currentLocation.coordinate.latitude;
if(currentLocation.coordinate.longitude > maxLon)
maxLon = currentLocation.coordinate.longitude;
if(currentLocation.coordinate.longitude < minLon)
minLon = currentLocation.coordinate.longitude;
}
region.center.latitude = (maxLat + minLat) / 2;
region.center.longitude = (maxLon + minLon) / 2;
region.span.latitudeDelta = maxLat - minLat;
region.span.longitudeDelta = maxLon - minLon;
[mapView setRegion:region animated:YES];
}
-(void) showRouteFrom: (Place*) f to:(Place*) t {
if(routes) {
[mapView removeAnnotations:[mapView annotations]];
[routes release];
}
PlaceMark* from = [[[PlaceMark alloc] initWithPlace:f] autorelease];
PlaceMark* to = [[[PlaceMark alloc] initWithPlace:t] autorelease];
[mapView addAnnotation:from];
[mapView addAnnotation:to];
Reachability *reachability = [Reachability reachabilityForInternetConnection];
NetworkStatus internetStatus = [reachability currentReachabilityStatus];
if (internetStatus != NotReachable){
routes = [[self calculateRoutesFrom:from.coordinate to:to.coordinate] retain];
[self drawRoute];
[self centerMap];
}else{
[activityIndicator stopAnimating];
UIAlertView *alert =[[UIAlertView alloc]initWithTitle:#"Oops!" message:#"Railway server is either busy or not responding at the moment. Try again later." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
}
}
- (void)drawRoute
{
int numPoints = [routes count];
if (numPoints > 1)
{
CLLocationCoordinate2D* coords = malloc(numPoints * sizeof(CLLocationCoordinate2D));
for (int i = 0; i < numPoints; i++)
{
CLLocation* current = [routes objectAtIndex:i];
coords[i] = current.coordinate;
}
objPolyline = [MKPolyline polylineWithCoordinates:coords count:numPoints];
free(coords);
[mapView addOverlay:objPolyline];
[mapView setNeedsDisplay];
}
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MKPolylineView *thePolylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
thePolylineView.strokeColor = [UIColor colorWithRed:((float) 204.0 / 255.0f)green:((float) 7.0 / 255.0f)blue:((float) 40.0 / 255.0f)alpha:1.0f]; // <-- So important stuff here
thePolylineView.lineWidth = 5.0;
return thePolylineView;
}

Finding Path/Route Between two points on MapKit in iPhone

I am trying to find the path between two locations on Mapkit. All I have is two locations. Now I have to find the exact path between these points and draw a line between these points using MapKit. I have gone through several examples in which they are using .csv files. In that .csv file they have stored the latitude and longitude values of the full path and drawing line based on those values.
But here I am trying to draw a line without knowing the path. So is there any way to find the path dynamically and draw a line?
Below is the code to finds path & draws line between two locations.
To implement below class:
_mapRecord = [[PSMapDirection alloc] initWithFrame:CGRectMake(0.0, 49.0, 320.0, 411.0)];
[self.view addSubview:_mapRecord];
MapDirection.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import "RegexKitLite.h"
#interface MapDirection : UIView<MKMapViewDelegate>
{
MKMapView* mapView;
NSArray* routes;
BOOL isUpdatingRoutes;
}
-(void) showRouteFrom: (MKAnnotation*) f to:(MKAnnotation*) t;
#end
MapDirection.m
#import "MapDirection.h"
#interface MapDirection()
-(NSArray*) calculateRoutesFrom:(CLLocationCoordinate2D) from to: (CLLocationCoordinate2D) to;
-(void) centerMap;
#end
- (id) initWithFrame:(CGRect) frame
{
self = [super initWithFrame:frame];
if (self != nil)
{
mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
mapView.showsUserLocation = NO;
[mapView setDelegate:self];
[self addSubview:mapView];
}
return self;
}
- (NSMutableArray *)decodePolyLine: (NSMutableString *)encoded
{
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\" options:NSLiteralSearch range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len)
{
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do
{
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do
{
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
//printf("[%f,", [latitude doubleValue]);
//printf("%f]", [longitude doubleValue]);
CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:loc];
}
return array;
}
-(NSArray*) calculateRoutesFrom:(CLLocationCoordinate2D) f to: (CLLocationCoordinate2D) t
{
NSString* saddr = [NSString stringWithFormat:#"%f,%f", f.latitude, f.longitude];
NSString* daddr = [NSString stringWithFormat:#"%f,%f", t.latitude, t.longitude];
NSString* apiUrlStr = [NSString stringWithFormat:#"http://maps.google.com/maps?output=dragdir&saddr=%#&daddr=%#", saddr, daddr];
NSURL* apiUrl = [NSURL URLWithString:apiUrlStr];
//NSLog(#"api url: %#", apiUrl);
NSError* error = nil;
NSString *apiResponse = [NSString stringWithContentsOfURL:apiUrl encoding:NSASCIIStringEncoding error:&error];
NSString *encodedPoints = [apiResponse stringByMatching:#"points:\\\"([^\\\"]*)\\\"" capture:1L];
return [self decodePolyLine:[encodedPoints mutableCopy]];
}
-(void) centerMap
{
MKCoordinateRegion region;
CLLocationDegrees maxLat = -90.0;
CLLocationDegrees maxLon = -180.0;
CLLocationDegrees minLat = 90.0;
CLLocationDegrees minLon = 180.0;
for(int idx = 0; idx < routes.count; idx++)
{
CLLocation* currentLocation = [routes objectAtIndex:idx];
if(currentLocation.coordinate.latitude > maxLat)
maxLat = currentLocation.coordinate.latitude;
if(currentLocation.coordinate.latitude < minLat)
minLat = currentLocation.coordinate.latitude;
if(currentLocation.coordinate.longitude > maxLon)
maxLon = currentLocation.coordinate.longitude;
if(currentLocation.coordinate.longitude < minLon)
minLon = currentLocation.coordinate.longitude;
}
region.center.latitude = (maxLat + minLat) / 2.0;
region.center.longitude = (maxLon + minLon) / 2.0;
region.span.latitudeDelta = 0.01;
region.span.longitudeDelta = 0.01;
region.span.latitudeDelta = ((maxLat - minLat)<0.0)?100.0:(maxLat - minLat);
region.span.longitudeDelta = ((maxLon - minLon)<0.0)?100.0:(maxLon - minLon);
[mapView setRegion:region animated:YES];
}
-(void) showRouteFrom: (MKAnnotation*) f to:(MKAnnotation*) t
{
if(routes)
{
[mapView removeAnnotations:[mapView annotations]];
}
[mapView addAnnotation:f];
[mapView addAnnotation:t];
routes = [self calculateRoutesFrom:f.coordinate to:t.coordinate];
NSInteger numberOfSteps = routes.count;
CLLocationCoordinate2D coordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++)
{
CLLocation *location = [routes objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coordinates[index] = coordinate;
}
MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfSteps];
[mapView addOverlay:polyLine];
[self centerMap];
}
#pragma mark MKPolyline delegate functions
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
polylineView.strokeColor = [UIColor purpleColor];
polylineView.lineWidth = 5.0;
return polylineView;
}
#end
Sample Map Route for starting points - "41.967659,-87.627869" and destination points - "41.574361,-91.083069"
Here The way in which I am able to draw direction between two points(Location).
First of all download GoogleMap sdk from this link and integrate into your application.
Now API key required and you can create as par given guidelines on this link.
Below are Code that draw direction on google map between two location.
-(NSArray*) calculateRoutesFrom:(CLLocationCoordinate2D) f to: (CLLocationCoordinate2D) t {
NSString* saddr = [NSString stringWithFormat:#"%f,%f", f.latitude, f.longitude];
NSString* daddr = [NSString stringWithFormat:#"%f,%f", t.latitude, t.longitude];
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=%#&destination=%#&sensor=false&avoid=highways&mode=driving",saddr,daddr]];
NSError *error=nil;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init] ;
[request setURL:url];
[request setHTTPMethod:#"POST"];
NSURLResponse *response = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error: &error];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSDictionary * dic = [NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONWritingPrettyPrinted error:nil];
return [self decodePolyLine:[self parseResponse:dic]];
}
- (NSString *)parseResponse:(NSDictionary *)response {
NSArray *routes = [response objectForKey:#"routes"];
NSDictionary *route = [routes lastObject];
if (route) {
NSString *overviewPolyline = [[route objectForKey:
#"overview_polyline"] objectForKey:#"points"];
return overviewPolyline;
}
return #"";
}
-(NSMutableArray *)decodePolyLine:(NSString *)encodedStr {
NSMutableString *encoded = [[NSMutableString alloc]
initWithCapacity:[encodedStr length]];
[encoded appendString:encodedStr];
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\"
options:NSLiteralSearch
range:NSMakeRange(0,
[encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1)
: (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1)
: (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
CLLocation *location = [[CLLocation alloc] initWithLatitude:
[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:location];
}
return array;
}
- (void)loadMapViewWithDirection {
float lat = 23.050671;
float lng = 72.541351;
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:lat
longitude:lng
zoom:10];
GMSMapView * mapView = [GMSMapView mapWithFrame:CGRectMake(0, 75, 320, self.view.frame.size.height-kHeaderRect.size.height) camera:camera];
self.mapView.myLocationEnabled = YES;
float sourceLatitude = 23.050671;
float sourceLongitude = 72.541351;
float destLatitude = 23.036138;
float destLongitude = 72.603836;
GMSMarker *sourceMarker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(sourceLatitude, sourceLongitude);
marker.map = self.mapView;
GMSMarker *destMarker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(destLatitude, destLongitude);
marker.map = self.mapView;
self.mapView.delegate = self;
[self drawDirection:CLLocationCoordinate2DMake(sourceLatitude, sourceLongitude) and:CLLocationCoordinate2DMake(destLatitude, destLongitude)];
[self.view addSubview:self.mapView];
}
- (void) drawDirection:(CLLocationCoordinate2D)source and:(CLLocationCoordinate2D) dest {
GMSPolyline *polyline = [[GMSPolyline alloc] init];
GMSMutablePath *path = [GMSMutablePath path];
NSArray * points = [self calculateRoutesFrom:source to:dest];
NSInteger numberOfSteps = points.count;
for (NSInteger index = 0; index < numberOfSteps; index++)
{
CLLocation *location = [points objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
[path addCoordinate:coordinate];
}
polyline.path = path;
polyline.strokeColor = [UIColor redColor];
polyline.strokeWidth = 2.f;
polyline.map = self.mapView;
// Copy the previous polyline, change its color, and mark it as geodesic.
polyline = [polyline copy];
polyline.strokeColor = [UIColor greenColor];
polyline.geodesic = YES;
polyline.map = self.mapView;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self loadMapViewWithDirection];
}
You can refer this code, it does exactly what you want.EDIT: and this also
I don't think you can do this locally. Implementing an algoritm for finding a path between two gps points requires a lot of input data (data from the maps) and you don't have this. Only a map provider can afford to implement such algoritm and expose an API for using it. I think Google have routing API, but I haven't played around with it...
https://developers.google.com/maps/documentation/directions/
Note that the TOS say that you have to display the results on a Google map, so you'll have to disable the functionality on the next iOS release

road map from location A to location B by latitude and longitude

I am doing work with map and location. I want to have road map from one location to another location. I am providing latitude and longitude of both the location(destination and source). So please help me to have this map.
I read about Google map api but I didn't find perfect answer.
Use below URL of google map API to find the road map route between two locations
http://maps.google.com/?saddr=STARTINGADDRESS&daddr=DESTINATIONADDRESS
First you have to take the directions from Google. Like this:
NSError *error = nil;
NSString *directionsInJSON = [NSString stringWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%f,%f&sensor=true",start.coordinate.latitude , start.coordinate.longitude , destination.coordinate.latitude, destination.coordinate.longitude]]encoding:NSUTF8StringEncoding error:&error];
After that , parse the JSON you got above:
if (error == nil)
{
NSError *JSONError = nil;
SBJsonParser *JSONParser = [[SBJsonParser alloc] init];
id directions = [JSONParser objectWithString:directionsInJSON error:&JSONError];
if (JSONError == nil)
{
directions = (NSDictionary*)directions;
NSString *status = [directions objectForKey:#"status"];
if ([status isEqualToString:#"OK"])
{
NSArray *routes = [directions objectForKey:#"routes"];
NSDictionary *route = [routes objectAtIndex:0];
NSDictionary *polylineOverview = [route objectForKey:#"overview_polyline"];
NSString *polylinePoints = [polylineOverview objectForKey:#"points"];
NSArray *decodedPolyline = [self decodePolyLine:polylinePoints];
[self loadRouteWithPoints:decodedPolyline];
}
else
{
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:#"No routes found" message:#"Sorry , we couldn't find any routes between you two." delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil] autorelease];
[alert show];
}
}
}
else
{
NSLog(#"error: %#",error.description);
}
Now you need these methods:
-(void) loadRouteWithPoints:(NSArray *) routes
{
CLLocationCoordinate2D coords[[routes count]];
for(int i = 0; i < routes.count; i++)
{
CLLocation* loc = (CLLocation*)[routes objectAtIndex:i];//[NSKeyedUnarchiver unarchiveObjectWithData:[routes objectAtIndex:i]];
CLLocationCoordinate2D c;
c.latitude = loc.coordinate.latitude;
c.longitude = loc.coordinate.longitude;
coords[i] = c;
}
MKPolyline *line = [[MKPolyline polylineWithCoordinates:(CLLocationCoordinate2D*)coords count:[routes count]] retain];
[self.mapsView addOverlay:line];
}
And:
- (NSMutableArray *)decodePolyLine: (NSString *)encoded
{
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
NSInteger lat=0;
NSInteger lng=0;
while (index < len)
{
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do
{
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do
{
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[[NSNumber alloc] initWithFloat:lat * 1e-5] autorelease];
NSNumber *longitude = [[[NSNumber alloc] initWithFloat:lng * 1e-5] autorelease];
CLLocation *loc = [[[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]] autorelease];
[array addObject:loc];
}
return array;
}
Voila!
Cheers!

Draw Route on google Map in iphone

I want to draw route on mapview using latitude and longitude. how is it possible to draw?
Here is my code. but it is not working. i have added location in points Mutable array. and after that called drawRoute function to draw route between that location.
- (void)viewDidLoad {
[super viewDidLoad];
CLLocationCoordinate2D location;
location.latitude = (double) 23.00000;
location.longitude = (double) 73.00000;
CLLocationCoordinate2D location2;
location2.latitude = (double) 73.00000;
location2.longitude = (double) 23.00000;
CLLocation *locationPoint1 = [[CLLocation alloc]initWithLatitude:location.latitude longitude:location.longitude];
CLLocation *locationPoint2 = [[CLLocation alloc]initWithLatitude:location2.latitude longitude:location2.longitude];
[self.points addObject:locationPoint1];
[self.points addObject:locationPoint2];
[self performSelector:#selector(drowRoute)];
}
-(void)drowRoute{
CGContextRef context = UIGraphicsGetCurrentContext();
// CGContextSetStrokeColorWithColor(context, [[UIColor blueColor]CGColor]);
CGContextSetLineWidth(context, 2.0);
for(int idx = 0; idx < self.points.count; idx++)
{
CLLocation* location = [self.points objectAtIndex:idx];
CGPoint point = [mapView convertCoordinate:location.coordinate toPointToView:self.view];
if(idx == 0)
{
// move to the first point
CGContextMoveToPoint(context, point.x, point.y);
}
else
{
CGContextAddLineToPoint(context, point.x, point.y);
}
}
CGContextStrokePath(context);
}
I use it using Goggle Map Services. You just have to pass longitude and latitude as a parameter to URL and rest is taken care by Google maps.
- (void)viewDidLoad
{
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
[locationManager startUpdatingLocation];
NSString *url = [NSString stringWithFormat: #"http://maps.google.com/maps?saddr=%f,%f&daddr=%f,%f",c_lat,c_long,lat,lat];
//saddr= we pass source address long, lat.
//daddr= we pass destination address long, lat.
//--------use this if you have current long,lat and destination's address or street name etc...
NSString* url = [NSString stringWithFormat: #"http://maps.google.com/maps?saddr=%f,%f&daddr=%#",
currentLocation.latitude, currentLocation.longitude,
[address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
//------------------------------------------------------------------------------
[[UIApplication sharedApplication] openURL: [NSURL URLWithString:url]]; // this line will open Google map on Maps application on device and in Safari in Simulator.
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
curntloc = [[CLLocation alloc] initWithLatitude:newLocation.coordinate.latitude longitude:newLocation.coordinate.longitude];
NSLog(#"in func--> %f %f",curntloc.coordinate.latitude, curntloc.coordinate.longitude);
}
Use following code:
-(NSMutableArray *)decodePolyLine: (NSMutableString *)encoded {
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\"
options:NSLiteralSearch
range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[[NSNumber alloc] initWithFloat:lat * 1e-5] autorelease];
NSNumber *longitude = [[[NSNumber alloc] initWithFloat:lng * 1e-5] autorelease];
CLLocation *loc = [[[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]] autorelease];
[array addObject:loc];
}
return array;
}
-(NSArray*) calculateRoutesFrom:(CLLocationCoordinate2D) f to: (CLLocationCoordinate2D) t {
NSString* saddr = [NSString stringWithFormat:#"%f,%f", f.latitude, f.longitude];
NSString* daddr = [NSString stringWithFormat:#"%f,%f", t.latitude, t.longitude];
NSString* apiUrlStr = [NSString stringWithFormat:#"http://maps.google.com/maps?output=dragdir&saddr=%#&daddr=%#", saddr, daddr];
NSURL* apiUrl = [NSURL URLWithString:apiUrlStr];
NSString *apiResponse = [NSString stringWithContentsOfURL:apiUrl];
NSString* encodedPoints = [apiResponse stringByMatching:#"points:\\\"([^\\\"]*)\\\"" capture:1L];
return [self decodePolyLine:[encodedPoints mutableCopy]];
}
-(void) centerMap {
MKCoordinateRegion region;
CLLocationDegrees maxLat = -90;
CLLocationDegrees maxLon = -180;
CLLocationDegrees minLat = 90;
CLLocationDegrees minLon = 180;
for(int idx = 0; idx < routes.count; idx++)
{
CLLocation* currentLocation = [routes objectAtIndex:idx];
if(currentLocation.coordinate.latitude > maxLat)
maxLat = currentLocation.coordinate.latitude;
if(currentLocation.coordinate.latitude < minLat)
minLat = currentLocation.coordinate.latitude;
if(currentLocation.coordinate.longitude > maxLon)
maxLon = currentLocation.coordinate.longitude;
if(currentLocation.coordinate.longitude < minLon)
minLon = currentLocation.coordinate.longitude;
}
region.center.latitude = (maxLat + minLat) / 2;
region.center.longitude = (maxLon + minLon) / 2;
region.span.latitudeDelta = maxLat - minLat;
region.span.longitudeDelta = maxLon - minLon;
[mapView setRegion:region animated:YES];
}
-(void) calculate_distance{
float target = [location1 distanceFromLocation:location2]/1000;
text2=[NSString stringWithFormat:#"%fkm",target];
routes = [[self calculateRoutesFrom:location1.coordinate to:location2.coordinate] retain];
if([routes count]!=0){
[self updateRouteView];
[self centerMap];
UIAlertView* alert1=[[UIAlertView alloc]initWithTitle:#"MESSAGE" message:text2 delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert1 show];
[alert1 release];
}
else{
UIAlertView* alert=[[UIAlertView alloc]initWithTitle:#"MESSAGE" message:#"We could not draw direction between your desired locations" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
location1=0;
location2=0;
}
-(void) updateRouteView {
CGContextRef context = CGBitmapContextCreate(nil,
routeView.frame.size.width,
routeView.frame.size.height,
8,
4 * routeView.frame.size.width,
CGColorSpaceCreateDeviceRGB(),
kCGImageAlphaPremultipliedLast);
CGContextSetStrokeColorWithColor(context, lineColor.CGColor);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);
CGContextSetLineWidth(context, 3.0);
for(int i = 0; i < routes.count; i++) {
CLLocation* location = [routes objectAtIndex:i];
CGPoint point = [mapView convertCoordinate:location.coordinate toPointToView:routeView];
if(i == 0) {
CGContextMoveToPoint(context, point.x, routeView.frame.size.height - point.y);
} else {
CGContextAddLineToPoint(context, point.x, routeView.frame.size.height - point.y);
}
}
CGContextStrokePath(context);
CGImageRef image = CGBitmapContextCreateImage(context);
UIImage* img = [UIImage imageWithCGImage:image];
routeView.image = img;
CGContextRelease(context);
}
Here is an example source code for drawing route on the map using lat,long coordinates.
http://developer.apple.com/library/ios/#samplecode/Breadcrumb/Introduction/Intro.html
This is how i learnt to do the very task.
Besides, to draw lines, in this post you will find classes for annotation. Check out the source code in the post, it will be more then sufficient to help you i hope.
By using the classes in the second link i have post, you will just have to provide the coordinates (lat,long) and the classes will do the rest :)
I use the code given below to draw a route between two locations:
- (void)fetchPolylineWithOrigin:(CLLocation *)origin destination:(CLLocation *)destination {
NSString *originString = [NSString stringWithFormat:#"%f,%f", origin.coordinate.latitude, origin.coordinate.longitude];
NSString *destinationString = [NSString stringWithFormat:#"%f,%f", destination.coordinate.latitude, destination.coordinate.longitude];
NSString *directionsAPI = #"https://maps.googleapis.com/maps/api/directions/json?";
NSString *directionsUrlString = [NSString stringWithFormat:#"%#&origin=%#&destination=%#&mode=driving", directionsAPI, originString, destinationString];
NSURL *directionsUrl = [NSURL URLWithString:directionsUrlString];
NSURLSessionDataTask *fetchDirectionsTask = [[NSURLSession sharedSession] dataTaskWithURL:directionsUrl completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
if(error) {
//Error in fetching poline
return;
}
NSArray *routesArray = [json objectForKey:#"routes"];
if ([routesArray count] > 0) {
NSDictionary *routeDict = [routesArray objectAtIndex:0];
NSDictionary *routeOverviewPolyline = [routeDict objectForKey:#"overview_polyline"];
NSString *points = [routeOverviewPolyline objectForKey:#"points"];
GMSPath *path = [GMSPath pathFromEncodedPath:points];
[self drawPath:path];
}
}];
[fetchDirectionsTask resume];
}
- (void)drawPath:(GMSPath *)newPath {
GMSPolyline *polyline = [GMSPolyline polylineWithPath:newPath];
polyline.strokeColor =PathColor;
polyline.strokeWidth = 2.5;
polyline.geodesic = YES;
NSArray *styles = #[[GMSStrokeStyle solidColor:PathColor],
[GMSStrokeStyle solidColor:PathColor]];
NSArray *lengths = #[#100000, #50000];
polyline.spans = GMSStyleSpans(polyline.path, styles, lengths, kGMSLengthRhumb);
polyline.map = _mapView;
}

Calculating driving distance to a particular coordinate

Is there a way where i could get the driving distance to a particular geo-cordinate ? I am aware that i have to use http://maps.googleapis.com/maps/api/directions/output?parameters and get a JSON output to get the results.
Is there a tutorial that explains how to get this done? or any sample code where i start on?
You may try the following. This code fetches all directions (even the alternate ones) returned by Google Directions Services. You can get the distance in step 2 (parsing response)
Step 1: Enter the From and To Locations
NSMutableString *googleURL = [[NSMutableString alloc] initWithString:[NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=%#&destination=%#&sensor=true&alternatives=true", searchFrom.text, searchTo.text]];
NSURL *url = [NSURL URLWithString:googleURL];
[googleURL release];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[NSURLConnection connectionWithRequest:request delegate:self];
request = nil;
responseData = [[NSMutableData alloc] init];
Step 2: When you get the response of the query made, parse the result
- (id)parseResponseWithDictionary:(NSDictionary *)dictResponse {
if ([[dictResponse objectForKey:#"status"] isEqualToString:kGoogleDirectionsStatusOK]) {
NSArray *listRoutes = (NSArray *)[dictResponse objectForKey:#"routes"];
NSMutableString *result = nil;
NSMutableArray *listPolylines = nil;
for (NSDictionary *dictRouteValues in listRoutes) {
NSDictionary *dictPolyline = [dictRouteValues objectForKey:#"overview_polyline"];
if (!result) {
result = [[NSMutableString alloc] init];
}
[result appendString:[dictPolyline objectForKey:#"points"]];
if (!listPolylines) {
listPolylines = [[NSMutableArray alloc] init];
}
[listPolylines addObject:result];
[result release];
result = nil;
}
return [listPolylines autorelease];
}
else {
NSString *error = #"No result found. Please check start and end location again!";
return error;
}
return nil;
}
Step 3: Decode each polyline in the polyline list. This will give the path coordinates.
-(NSMutableArray *)decodePolyLine:(NSMutableString *)encoded {
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\"
options:NSLiteralSearch
range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *listCoordinates = [[[NSMutableArray alloc] init] autorelease];
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
//CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[listCoordinates addObject:[NSString stringWithFormat:#"%f,%f", [latitude floatValue], [longitude floatValue]]];
//[loc release];
[latitude release];
[longitude release];
}
return listCoordinates;
}
this newer tutorial/sample code using CoreLocation and MapKit helped me a bunch.