GoogleMap API Gives Wrong Coordinates for Direction between two Points

こ雲淡風輕ζ 提交于 2019-11-28 12:54:19

Below answer is for smooth path between two location with help of @A Báo:

-(void)viewDidLoad {

    // Create a GMSCameraPosition that tells the map to display the

    GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:21.718472 longitude:73.030422 zoom:6];
    mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera];
    mapView_.delegate=self;
    mapView_.myLocationEnabled = YES;
    mapView_.settings.myLocationButton=YES;
    mapView_.settings.indoorPicker=NO;
    mapView_.settings.compassButton=YES;

    self.view = mapView_;

    NSString *str=@"http://maps.googleapis.com/maps/api/directions/json?origin=Bharuch,gujarat&destination=vadodara,gujarat&sensor=false";

    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"];

    @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 = mapView_;

    }
    @catch (NSException * e) {
        // TODO: show error
    }
}

-(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;
}

Screenshot of this code you can compare it with previous screenshot which i used in asking Question:

I did add GMSMarker to each point get on steps array and I sure that use steps array start_location and end_location not enough to show direction in your map. here is code I did edit from your code

NSString *str=@"http://maps.googleapis.com/maps/api/directions/json?origin=bharuch,gujarat&destination=vadodara,gujarat&sensor=false";

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"];

NSMutableDictionary *legs=[[[latestRoutes objectAtIndex:0] objectForKey:@"legs"] objectAtIndex:0];

NSArray *steps=[legs objectForKey:@"steps"];

NSString *startLocation,*endLocation,*totalDistance,*totalDuration;

CLLocationCoordinate2D startLoc,endLoc;

startLocation = [legs objectForKey:@"start_address"];

endLocation = [legs objectForKey:@"end_address"];

totalDistance = [[legs objectForKey:@"distance"] objectForKey:@"text"];

totalDuration = [[legs objectForKey:@"duration"] objectForKey:@"text"];

startLoc=CLLocationCoordinate2DMake([[[legs objectForKey:@"start_location"] objectForKey:@"lat"] doubleValue], [[[legs objectForKey:@"start_location"] objectForKey:@"lng"] doubleValue]);

NSMutableDictionary *stopLegs=[[[latestRoutes objectAtIndex:0] objectForKey:@"legs"] objectAtIndex:0];
endLoc=CLLocationCoordinate2DMake([[[stopLegs objectForKey:@"end_location"] objectForKey:@"lat"] doubleValue], [[[stopLegs objectForKey:@"end_location"] objectForKey:@"lng"] doubleValue]);

NSMutableDictionary *tempDict;

if ([steps count]!=0) {
    // add marker
    NSDictionary *step;
    for (int i= 0; i < steps.count; i++) {
        step = [steps objectAtIndex:i];
        NSDictionary *location = [step objectForKey:@"start_location"];
        double lat = [[location objectForKey:@"lat"] doubleValue];
        double lng = [[location objectForKey:@"lng"] doubleValue];
        GMSMarker *marker = [[GMSMarker alloc] init];
        marker.position = CLLocationCoordinate2DMake(lat, lng);
        marker.snippet = [NSString stringWithFormat:@"point (%d)", i+1];
        marker.map = mapView_;
    }
    NSDictionary *location = [step objectForKey:@"end_location"];
    double lat = [[location objectForKey:@"lat"] doubleValue];
    double lng = [[location objectForKey:@"lng"] doubleValue];
    GMSMarker *marker = [[GMSMarker alloc] init];
    marker.position = CLLocationCoordinate2DMake(lat, lng);
    marker.snippet = [NSString stringWithFormat:@"point (%d)", steps.count];
    marker.map = mapView_;

    // continue draw map
    GMSMutablePath *path = [GMSMutablePath path];

    for(int idx = 0; idx < [steps count]+2; idx++){

        CLLocationCoordinate2D workingCoordinate;

        if (idx==0) {

            workingCoordinate=startLoc;

            [path addCoordinate:workingCoordinate];

        }
        else if (idx==[steps count]+1){

            workingCoordinate=endLoc;

            [path addCoordinate:workingCoordinate];
        }
        else{

            workingCoordinate=CLLocationCoordinate2DMake([[[[steps objectAtIndex:idx-1] objectForKey:@"start_location"] objectForKey:@"lat"] floatValue], [[[[steps objectAtIndex:idx-1] objectForKey:@"start_location"] objectForKey:@"lng"] floatValue]);

            [path addCoordinate:workingCoordinate];

        }
        tempDict = nil;
    }
    // create the polyline based on the array of points.

    GMSPolyline *rectangle = [GMSPolyline polylineWithPath:path];

    rectangle.strokeWidth=5.0;

    rectangle.map = mapView_;
}

you can see betwen point 12 and point 13 have a big distance (60.2 km). but it just one path. I did find out that if you want to show approximate (smoothed) path of the resulting directions. you need use "overview_polyline" field. overview_polyline: contains an object holding an array of encoded points that represent an approximate (smoothed) path of the resulting directions. this link google map develop helpful for you. So work for you is find method to decode data from "overview_polyline" to get correct path between two point. I definitely it's true way to resolve your problem because I did check tool to decode "overview_polyline" at Encoded Polyline Algorithm Format This Image what I got from decode:

To decode polyne string you can find at this block http://objc.id.au/post/9245961184/mapkit-encoded-polylines

  • Continue, with code from @jayraj m.g. Below answer is for smooth path between two location
-(void)viewDidLoad {

    // Create a GMSCameraPosition that tells the map to display the

    GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:21.718472 longitude:73.030422 zoom:6];
    mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera];
    mapView_.delegate=self;
    mapView_.myLocationEnabled = YES;
    mapView_.settings.myLocationButton=YES;
    mapView_.settings.indoorPicker=NO;
    mapView_.settings.compassButton=YES;

    self.view = mapView_;

    NSString *str=@"http://maps.googleapis.com/maps/api/directions/json?origin=Bharuch,gujarat&destination=vadodara,gujarat&sensor=false";

    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"];

    @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 = mapView_;

    }
    @catch (NSException * e) {
        // TODO: show error
    }
}

-(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;
}

Screenshot of this code you can compare it with previous screenshot which i used in asking Question:

Thanks @jayraj m.g.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!