I'm using mapKit to draw a route from point to point. I did it.
But i want to get route length NOT the distance as straight line.
nextView.startPoint = [NSString stringWithFormat:#"%f,%f", userLatitude , userLongitude];
nextView.endPoint = [NSString stringWithFormat:#"%f,%f", 30.793636, 31.009641];
[diretions loadWithStartPoint:startPoint endPoint:endPoint options:options];
Aloso i want to give it a mid point to path through.
To do that you are going to have to use a directions API, preferably Google Directions API. You should look at that link and read it through, Apple does not have a built in direction API. You can send it a request and ask for JSON response, I would use AFNetworking to make like easier (on Github) and JSONKit also on Github for that. Then send a request and parse the JSON response. In the response you need the encoded points, which is a set of many coordinates that basically traces the route. You would then need to display that on an overlay. Here is some sample code, but before you copy and paste this in make sure you read the GDirections API Site, you will understand everything MUCH easier and can learn how to do more:
// DRAG IN AFNETWORKING FILES AND JSON KIT FILES TO YOUR PROJECT AND ALSO IMPORT THE MAP KIT AND CORE LOCATION FRAMEWORKS
// IMPORT FILES
#import "StringHelper.h"
#import "JSONKit.h"
#import "AFJSONRequestOperation.h"
#import "AFHTTPClient.h"
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
// DECLARE MUTABLE ARRAY IN .H:
NSMutableArray *_path;
// ADD THIS CODE TO WHEN YOU WANT TO REQUEST FOR DIRECTIONS
AFHTTPClient *_httpClient = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:#"http://maps.googleapis.com/"]];
[_httpClient registerHTTPOperationClass: [AFJSONRequestOperation class]];
[_httpClient setDefaultHeader:#"Accept" value:#"application/json"];
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
[parameters setObject:[NSString stringWithFormat:#"%f,%f", location.coordinate.latitude, location.coordinate.longitude] forKey:#"origin"];
[parameters setObject:[NSString stringWithFormat:#"%f,%f", location2.coordinate.latitude, location2.coordinate.longitude] forKey:#"destination"];
[parameters setObject:#"false" forKey:#"sensor"];
[parameters setObject:#"driving" forKey:#"mode"];
[parameters setObject:#"metric" forKey: #"units"];
NSMutableURLRequest *request = [_httpClient requestWithMethod:#"GET" path: #"maps/api/directions/json" parameters:parameters];
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
AFHTTPRequestOperation *operation = [_httpClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSInteger statusCode = operation.response.statusCode;
if (statusCode == 200) {
[self parseResponse:responseObject];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) { }];
[_httpClient enqueueHTTPRequestOperation:operation];
// NOW ADD THE PARSERESPONSE METHOD
- (void)parseResponse:(NSDictionary *)response {
NSString *status = [response objectForKey: #"status"];
NSArray *routes = [response objectForKey:#"routes"];
NSDictionary *routePath = [routes lastObject];
if (routePath) {
NSString *overviewPolyline = [[routePath objectForKey: #"overview_polyline"] objectForKey:#"points"];
_path = [self decodePolyLine:overviewPolyline];
NSInteger numberOfSteps = _path.count;
CLLocationCoordinate2D coordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++) {
CLLocation *location = [_path objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coordinates[index] = coordinate;
}
polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfSteps];
[self.mapView addOverlay:polyLine];
}
}
// IMPLEMENTING THE DECODEPOLYLINE METHOD:
-(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;
}
// IMPLEMENTING THE VIEWFOROVERLAY DELEGATE METHOD (MAKE SURE TO SET YOUR MAP VIEW'S DELEGATE TO SELF OR THIS WONT GET CALLED)
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
polylineView.strokeColor = [UIColor blueColor];
polylineView.lineWidth = 5.0;
polylineView.alpha = 0.7;
return polylineView;
}
And that should get your directional routes up and running!
Related
I am trying to add multiple waypoints to my google directions request.
When I add a single waypoint like
https://maps.googleapis.com/maps/api/directions/json?&origin=51.507679,-0.125004&waypoints=51.524151,-0.123174&destination=51.495777,-0.108642&mode=walking
it works fine but when I try to add multiple waypoints like
https://maps.googleapis.com/maps/api/directions/json?&origin=51.606502,0.527309&waypoints=51.507679,-0.125004|51.524151,-0.123174&destination=51.495777,-0.108642&mode=walking
i receive a 'unsupported URL' error. What is the correct way to add multiple waypoints? Thanks
Its very simple, Just replace '|' with '%%7C'
Your updated url will be :
https://maps.googleapis.com/maps/api/directions/json?&origin=51.606502,0.527309&waypoints=51.507679,-0.125004%%7C51.524151,-0.123174&destination=51.495777,-0.108642&mode=walking
Happy Coding
I give you the solution step by step
First we should get the Google Map SDK
Drag the following bundles into your project (when prompted, select Copy items if needed):
Subspecs/Base/Frameworks/GoogleMapsBase.framework
Subspecs/Maps/Frameworks/GoogleMaps.framework
Subspecs/Maps/Frameworks/GoogleMapsCore.framework
Right-click GoogleMaps.framework in your project, and select Show In Finder.
Drag the GoogleMaps.bundle from the Resources folder into your project. When prompted, ensure Copy items into destination group's folder is not selected.
Select your project from the Project Navigator, and choose your application's target.
Open the Build Phases tab, and within Link Binary with Libraries, add the following frameworks:
GoogleMapsBase.framework
GoogleMaps.framework
GoogleMapsCore.framework
GoogleMapsM4B.framework (Premium Plan customers only)
Accelerate.framework
CoreData.framework
CoreGraphics.framework
CoreLocation.framework
CoreText.framework
GLKit.framework
ImageIO.framework
libc++.tbd
libz.tbd
OpenGLES.framework
QuartzCore.framework
SystemConfiguration.framework
UIKit.framework
Now Get the API key
Now you need to add following things in Plist
AppDelegate.m
#import GoogleMaps;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[GMSServices provideAPIKey:#"YOUR API KEY"];
return YES;
}
ViewController.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <GoogleMaps/GoogleMaps.h>
#interface ViewController : UIViewController<CLLocationManagerDelegate,GMSMapViewDelegate>{
CLLocation *currentLocation;
}
#property (strong, nonatomic) IBOutlet UIView *viewMarker;
#property (nonatomic, strong) CLLocationManager *locationManager;
#property (nonatomic, strong) GMSMapView *mapView;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize viewMarker,locationManager,
#synthesize mapView;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
locationManager = [[CLLocationManager alloc]init];
locationManager.delegate = self;
locationManager.distanceFilter = 10;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
if([CLLocationManager locationServicesEnabled] == NO){
NSLog(#"Your location service is not enabled, So go to Settings > Location Services");
}
else{
NSLog(#"Your location service is enabled");
}
if ([locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[locationManager requestWhenInUseAuthorization];
}
[locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate method
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
currentLocation = [locations lastObject];
if (currentLocation != nil){
NSLog(#"The latitude value is - %#",[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude]);
NSLog(#"The logitude value is - %#",[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude]);
}
//Current
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:currentLocation.coordinate.latitude longitude: currentLocation.coordinate.longitude zoom:13];
self.mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
self.mapView.myLocationEnabled = YES;
self.mapView.delegate = self;
self.mapView.frame = viewMarker.bounds;
[viewMarker addSubview:self.mapView];
GMSMarker *marker1 = [[GMSMarker alloc] init];
//Current
marker1.position = CLLocationCoordinate2DMake(currentLocation.coordinate.latitude, currentLocation.coordinate.longitude);
marker1.icon = [UIImage imageNamed:#"boss-icon.png"];
marker1.map = self.spyMapView;
NSArray *arrLatLongValue = #[
#{
#"Latitude":#"12.9003",
#"Longitude":#"80.2278"
},
#{
#"Latitude":#"12.8447",
#"Longitude":#"80.2254"
},
#{
#"Latitude":#"12.7726",
#"Longitude":#"80.2488"
},
#{
#"Latitude":#"12.9171",
#"Longitude":#"80.1923"
}
];
NSString *strWayPoints = [NSString stringWithFormat:#"via:%f,%f", [arrLatLongValue[0][#"Latitude"] doubleValue], [arrLatLongValue[0][#"Longitude"] doubleValue]];
for(int j=0;j<arrLatLongValue.count;j++){
CLLocationCoordinate2D position = { [[arrLatLongValue[j] objectForKey:#"Latitude"] doubleValue], [[arrLatLongValue[j] objectForKey:#"Longitude"] doubleValue] };
GMSMarker *marker = [GMSMarker markerWithPosition:position];
marker.title = [NSString stringWithFormat:#"Marker %i", j];
marker.appearAnimation = YES;
marker.flat = YES;
if(j < 2)
marker.icon = [GMSMarker markerImageWithColor:[UIColor redColor]];
else if(j >= 2 && j < 4)
marker.icon = [GMSMarker markerImageWithColor:[UIColor purpleColor]];
else
marker.icon = [GMSMarker markerImageWithColor:[UIColor greenColor]];
if(j > 0)
strWayPoints = [NSString stringWithFormat:#"%#|via:%f,%f", strWayPoints, [arrLatLongValue[j][#"Latitude"] doubleValue], [arrLatLongValue[j][#"Longitude"] doubleValue]];
marker.map = self.mapView;
}
//Current
NSString *originString = [NSString stringWithFormat:#"%f,%f",currentLocation.coordinate.latitude, currentLocation.coordinate.longitude];
NSString *destinationString = [NSString stringWithFormat:#"%f,%f", #(12.9220085).doubleValue, #(80.0954032).doubleValue];
NSString *str = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/directions/json?origin=%#&destination=%#&waypoints=%#&key=YOUR API KEY",originString,destinationString,strWayPoints];
NSURL *url=[[NSURL alloc]initWithString:[str stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLSessionDataTask * dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if(data == nil) {
return;
}else{
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSArray* latestRoutes = [json objectForKey:#"routes"];
NSString *points=[[[latestRoutes objectAtIndex:0] objectForKey:#"overview_polyline"] objectForKey:#"points"];
#try {
// TODO: better parsing. Regular expression?
NSArray *temp= [self decodePolyLine:[points mutableCopy]];
GMSMutablePath *path = [GMSMutablePath path];
for(int idx = 0; idx < [temp count]; idx++){
CLLocation *location=[temp objectAtIndex:idx];
[path addCoordinate:location.coordinate];
}
// create the polyline based on the array of points.
GMSPolyline *rectangle = [GMSPolyline polylineWithPath:path];
rectangle.strokeWidth=5.0;
rectangle.map = self.spyMapView;
[locationManager stopUpdatingLocation];
}
#catch (NSException * e) {
// TODO: show erro
}
}
}];
[dataTask resume];
}
[locationManager stopUpdatingLocation];
}
pragma mark - Drawing Lines
-(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;
}
I have create a PolyLine in MapView. I tried to many times but did not draw. Ones a draw polyLine but that case run only simulator, I run in device and crash my app. and I already post my question here
I tried to many times and using lots of tutorials, please suggest any other tutorial.
I want to create a PolyLine in MapView using google direction URL. Starting point is my device location and end point is any lat long. so both points in centre draw a polyLine. That means create a root map starting point to end point draw a PolyLine.
Please help, Thank you
you can use google api for this
http://maps.googleapis.com/maps/api/directions/json?origin
in this api you have to pass lat log of your locations like this methode
-(NSArray*) calculateRoutes
{
NSString *baseUrl = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%f,%f&sensor=true",currentlatitude,currentlongitude,destination lat,destination log];
NSData *data=[NSData dataWithContentsOfURL:[NSURL URLWithString:baseUrl]];
if (data) {
NSDictionary *direction_dictionary=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
if (direction_dictionary) {
if ([[direction_dictionary valueForKey:#"status"] isEqualToString:#"OK"]) {
NSArray *routes_array=[direction_dictionary valueForKey:#"routes"];
if (routes_array) {
NSString *poinstEncoded_String=[[[routes_array firstObject] valueForKey:#"overview_polyline"] valueForKey:#"points"];
routes = [self decodePolyLine:[poinstEncoded_String mutableCopy]];
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];
dispatch_async(dispatch_get_main_queue(), ^{
[self.MapVw addOverlay:polyLine];
// add polyline here to your mapview
});
}
}
}
}
}
-(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];
CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:loc];
}
return array;
}
After getting response (Full example http://way2ios.com/development/ios-development-2/iphone-2/draw-polygon-mkmapview-stylus/):
– (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id )overlay
{
MKPolygonView *polygonView = [[MKPolygonView alloc] initWithPolygon:overlay];
polygonView.lineWidth = 5;
polygonView.strokeColor = [UIColor redColor];
polygonView.fillColor = [UIColor colorWithRed:0 green:191 blue:255 alpha:0.5];
mapView.userInteractionEnabled = YES;
return polygonView;
}
Check these also :
https://github.com/kadirpekel/MapWithRoutes and https://github.com/versluis/MapViewLines
I am working on an application where i want path between two locations.
I implemented some code. This is fine for short distance path but when i creating path for long distance like From Jaipur, Rajasthan, India to Jorhat, Aasam, India, my application get crashed.
This is my code
-(void)findPath{
[rectangle setMap:nil];
NSString* str = [NSMutableString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=%#&destination=%#&sensor=true", self.FromSearch, self.toSearch];
if (_travelMode==UICGTravelModeWalking) {
str=[str stringByAppendingFormat:#"&mode=walking"];
}
NSURL *url=[[NSURL alloc]initWithString:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSArray* latestRoutes = [json objectForKey:#"routes"];
NSString *points=[[[latestRoutes objectAtIndex:0] objectForKey:#"overview_polyline"] objectForKey:#"points"];
if ([latestRoutes isKindOfClass:[NSArray class]]&&latestRoutes.count==0) {
UIAlertView *alrt=[[UIAlertView alloc]initWithTitle:#"Alert" message:#"didn't find direction" delegate:nil cancelButtonTitle:#"ok" otherButtonTitles:nil, nil];
[alrt show];
return;
}
arrDistance =[[[json valueForKeyPath:#"routes.legs.steps.distance.text"] objectAtIndex:0]objectAtIndex:0];
totalDuration = [[[json valueForKeyPath:#"routes.legs.duration.text"] objectAtIndex:0]objectAtIndex:0];
totalDistance = [[[json valueForKeyPath:#"routes.legs.distance.text"] objectAtIndex:0]objectAtIndex:0];
arrDescription =[[[json valueForKeyPath:#"routes.legs.steps.html_instructions"] objectAtIndex:0] objectAtIndex:0];
dictRouteInfo=[NSDictionary dictionaryWithObjectsAndKeys:totalDistance,#"totalDistance",totalDuration,#"totalDuration",arrDistance ,#"distance",arrDescription,#"description", nil];
double srcLat=[[[[json valueForKeyPath:#"routes.legs.start_location.lat"] objectAtIndex:0] objectAtIndex:0] doubleValue];
double srcLong=[[[[json valueForKeyPath:#"routes.legs.start_location.lng"] objectAtIndex:0] objectAtIndex:0] doubleValue];
totalLat = [[NSMutableArray alloc]init];
totalLong = [[NSMutableArray alloc]init];
//for (int i = 0; i<arrDistance.count; i++) {
totalLat = [[[json valueForKeyPath:#"routes.legs.steps.start_location.lat"] objectAtIndex:0] objectAtIndex:0];
totalLong = [[[json valueForKeyPath:#"routes.legs.steps.start_location.lng"] objectAtIndex:0] objectAtIndex:0];
[self saveInfoForPath];
// }
CLLocationCoordinate2D location;
location.latitude = srcLat;
location.longitude = srcLong;
// mapView.camera = [GMSCameraPosition cameraWithTarget:location
// zoom:10];
//GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc]initWithPath:<#(GMSPath *)#>]
// [[GMSCoordinateBounds alloc] initWithCoordinate:vancouver coordinate:calgary];
#try {
// TODO: better parsing. Regular expression?
NSArray *temp= [self decodePolyLine:[points mutableCopy]];
GMSMutablePath *path = [GMSMutablePath path];
for(int idx = 0; idx < [temp count]; idx++)
{
CLLocation *location=[temp objectAtIndex:idx];
[path addCoordinate:location.coordinate];
}
// create the polyline based on the array of points.
rectangle = [GMSPolyline polylineWithPath:path];
rectangle.strokeWidth=5.0;
rectangle.map = mapView;
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc]initWithPath:path];
[mapView moveCamera:[GMSCameraUpdate fitBounds:bounds]];
}
#catch (NSException * e) {
// TODO: show error
}
}
decodePolyline() method coding
-(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;
}
What should i do. Please suggest.
You can try pathFromEncodedPath method in place of decodePolyLine for getting path from encodeString.
NSString *points=[[[latestRoutes objectAtIndex:0] objectForKey:#"overview_polyline"] objectForKey:#"points"];
polyline = [GMSPolyline polylineWithPath: [GMSPath pathFromEncodedPath: points]];
polyline.map = mapView;
polyline.strokeColor = [UIColor colorWithRed:0/255.0 green:4/255.0 blue:255/255.0 alpha:1.0];
polyline.strokeWidth = 4.0f;
I'm developing an iOS app which is using Google Directions API to draw routes on maps which are provided by Google Maps SDK. It works well on small distance although when I zoom the map camera very close I see that the route polylines are often getting out of the streets. When the distance is longer it's a real disaster and it's not following the streets curves if I zoom in. I'm getting the points from the overview-polyline which I receive from the Directions API but it seems like the polyline is not that poly as I want. On Android it works perfectly. Could it be that Google sends different directions to iOS than Android? Has some of you had the same problem as me?
EDIT:
-(int) requestDirecionsAndshowOnMap:(GMSMapView *)aMapView{
NSArray* mode=[[NSArray alloc]initWithObjects:#"transit",#"bicycling",#"walking",#"driving", nil];
NSString *depart=[[NSString alloc] initWithFormat:#""];
NSString *origin=[[NSString alloc] initWithFormat:#""];
NSString *destination=[[NSString alloc] initWithFormat:#""];
if (self.setLanguage)
self.setLanguage=[NSString stringWithFormat:#"language=%#",self.setLanguage];
else self.setLanguage=#"language=en";
if (searchModeOption==0) {
if (self.departDate==nil) {
self.departDate=[NSDate date];
}
depart=[NSString stringWithFormat:#"&departure_time=%i",(int)[self.departDate timeIntervalSince1970]];
}
if (self.origin) {
origin=[NSString stringWithFormat:#"origin=%#",self.origin];
}else if (self.originCoordinate.latitude && self.originCoordinate.longitude){
origin=[NSString stringWithFormat:#"origin=%f,%f",self.originCoordinate.latitude,self.originCoordinate.longitude];
}else{
NSLog(#"No origin setted");
return -1;
}
if (self.destination) {
destination=[NSString stringWithFormat:#"destination=%#",self.destination];
}else if (self.destinationCoordinate.latitude && self.destinationCoordinate.longitude){
destination=[NSString stringWithFormat:#"destination=%f,%f",self.destinationCoordinate.latitude,self.destinationCoordinate.longitude];
}else{
NSLog(#"No destination setted");
return -1;
}
NSString* URLforRequest=[[NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?%#&%#&sensor=false&%#&alternative=false&mode=%#%#",origin,destination,self.setLanguage,[mode objectAtIndex:searchModeOption],depart] stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding];
// NSLog(#"%#",URLforRequest);
NSURLRequest *requests = [NSURLRequest requestWithURL:[NSURL URLWithString:URLforRequest]];
[NSURLConnection sendAsynchronousRequest:requests queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
if (error==nil && data) {
// NSLog(#"%#",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
directions = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
if (error) {
NSLog(#"%#",error);
}
NSString* status=[directions objectForKey:#"status"];
NSLog(#"Status: %#", status);
if ([status isEqualToString:#"OK"]) {
[self decodeResult];
if (aMapView)
[self showOnMap:aMapView];
}
}else NSLog(#"%#",error);
[[NSNotificationCenter defaultCenter] postNotificationName:#"Request Done" object:nil];
}];
return 0;
}
-(void) decodeResult{
self.destination=[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"end_address"];
self.distance=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"distance"] objectForKey:#"text"] doubleValue];
self.duration=[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"duration"] objectForKey:#"text"];
//Get Array of Instructions
self.instrunctions=[[NSMutableArray alloc] init];
for (int n=0; n<[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"]count]; n++) {
[self.instrunctions addObject:[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"] objectAtIndex:n] objectForKey:#"html_instructions"]];
}
//Get Overview Polyline
NSString *polystring=[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"overview_polyline"] objectForKey:#"points"];
NSMutableArray* decodedpolystring=[self decodePolyLine:polystring];
int numberOfCC=[decodedpolystring count];
GMSMutablePath *path = [GMSMutablePath path];
for (int index = 0; index < numberOfCC; index++) {
CLLocation *location = [decodedpolystring objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
[path addLatitude:coordinate.latitude longitude:coordinate.longitude];
}
self.overviewPolilyne= [GMSPolyline polylineWithPath:path];
//Get Coordinates of origin and destination to be displayed on a map
float lat=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"]objectAtIndex:0] objectForKey:#"end_location"] objectForKey:#"lat"] floatValue];
float lng=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"]objectAtIndex:0] objectForKey:#"end_location"] objectForKey:#"lng"] floatValue];
CLLocationCoordinate2D tmp;
tmp.latitude=lat;
tmp.longitude=lng;
self.destinationCoordinate=tmp;
lat=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"]objectAtIndex:0] objectForKey:#"start_location"] objectForKey:#"lat"] floatValue];
lng=[[[[[[[directions objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"]objectAtIndex:0] objectForKey:#"start_location"] objectForKey:#"lng"] floatValue];
tmp.latitude=lat;
tmp.longitude=lng;
self.originCoordinate=tmp;
}
-(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)showOnMap:(GMSMapView *)aMapView{
GMSPolyline *polyline =self.overviewPolilyne;
polyline.strokeColor = [UIColor blueColor];
polyline.strokeWidth = 2.f;
//polyline.geodesic = YES;
polyline.map = aMapView; }
UPDATE:
I had to process every step's polyline, not just the overview-polyline. Now it works perfectly.
Here's the code I'm using now:
// Get polyline
GMSMutablePath *path = [GMSMutablePath path];
NSMutableArray *polyLinesArray = [[NSMutableArray alloc] init];
int zero=0;
NSArray *steps = [[[[[directions objectForKey:#"routes"] objectAtIndex:zero] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"];
for (int i=0; i<[[[[[[directions objectForKey:#"routes"] objectAtIndex:zero] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"steps"]count]; i++) {
NSString* encodedPoints =[[[steps objectAtIndex:i]objectForKey:#"polyline"]valueForKey:#"points"];
polyLinesArray = [self decodePolyLine:encodedPoints];
NSUInteger numberOfCC=[polyLinesArray count];
for (NSUInteger index = 0; index < numberOfCC; index++) {
CLLocation *location = [polyLinesArray objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
[path addLatitude:coordinate.latitude longitude:coordinate.longitude];
if (index==0) {
[self.coordinates addObject:location];
}
}
}
self.overviewPolilyne = [GMSPolyline polylineWithPath:path];
What I basically did before was that I was getting and working only with the information I'm receiving in the routes while if you check the JSON file you're receiving from Google Directions API, you'll see that you receive much more information in the <legs> and the <steps>. This is the information we need to produce the proper results and the right polyline.
Good luck! :)
I am creating a Navigation iPhone app that creates a polyline between the user location and the destination the user wants to go.
I am able to create the polyline. But what i need to do is as the user proceeds on the polyline, the polyline need to gradually decrease showing the user is on track. And i also need to detect if the user has strayed from the path.
For example, if the user has to go left but he doesn't, how will i detect that?
Any help will be appreciated. Thanks.
EDIT :
I have used the following code to draw the polyline for
-(void)drawPolyline{
//Draw polyline via the selected route
NSMutableArray *polys = [NSMutableArray array];
GMSMutablePath *path = [GMSMutablePath path];
NSDictionary *route=[routes objectAtIndex:0];
//self.strPolyPoints is a string
self.strPolyPoints=[[route objectForKey:#"overview_polyline"] objectForKey:#"points"];
NSArray *arrPoints=[self decodePolyLine];
for(CLLocation *location in arrPoints){
CLLocationCoordinate2D coordinate=location.coordinate;
[path addCoordinate:coordinate];
}
_lengths = #[#([path lengthOfKind:kGMSLengthGeodesic] / 40)];
GMSPolyline *polyline = [[GMSPolyline alloc] init];
polyline.path = path;
polyline.strokeColor = [UIColor blueColor];
polyline.geodesic = NO;
polyline.strokeWidth = 5;
polyline.map = mapView_;
[polys addObject:polyline];
_polys = polys;
[self tick];
}
- (void)tick {
//Create steps for polyline(dotted polylines)
for (GMSPolyline *poly in _polys) {
poly.spans =
GMSStyleSpans(poly.path, _styles, _lengths, kGMSLengthGeodesic, _pos);
}
_pos -= _step;
//Animate the polyline like moving from source to destination
if (kAnimate) {
__weak id weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 5),
dispatch_get_main_queue(),
^{ [weakSelf tick]; });
}
}
-(NSMutableArray *)decodePolyLine {
NSMutableString *encoded = [[NSMutableString alloc] initWithCapacity:[self.strPolyPoints length]];
[encoded appendString:self.strPolyPoints];
[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;
}
I think you have to draw the polyline from the user's location to the destination, on location change of the device remove the existing polyline and draw a new one with the user's current location. You could share some code that you have tried already so that I can help you in a better way.