iOS - 捕捉到具有超过 100 个坐标的道路 API
iOS - Snap To Road API with more than 100 coordinates
我知道如何使用 snap to road API 并解析响应,将其显示在地图上等。但是,snap to road API 有 100 的限制 coordinates/request.
假设我有一个包含 100 多个坐标的数组,并希望所有坐标都与道路对齐。
道路捕捉 API docs 描述了处理超过 100 个坐标时的解决方法,但它是 Java 代码(我认为)而且我真的不知道明白它。
我怎么能在 Objective-C 中做到这一点?
在我的实现中,我通过从我的数组中获取 100 个坐标的范围多次调用道路捕捉 api。然而,当在地图上绘制时,这会导致奇怪的多段线:
这是我的代码:
-(void)getDirectionsFrom:(CLLocation*)startLocation to:(CLLocation*)endLocation{
//Create placemarks from the passed in locations
MKPlacemark *start = [[MKPlacemark alloc] initWithCoordinate:locManager.location.coordinate addressDictionary:NULL];
MKPlacemark *finsih = [[MKPlacemark alloc] initWithCoordinate:endLocation.coordinate addressDictionary:NULL];
//Create direction request
MKDirectionsRequest *request = [[MKDirectionsRequest alloc]init];
[request setSource:[[MKMapItem alloc] initWithPlacemark:start]];
[request setDestination:[[MKMapItem alloc] initWithPlacemark:finsih]];
[request setTransportType:MKDirectionsTransportTypeAutomobile];
//Calculate directions
MKDirections *direction = [[MKDirections alloc]initWithRequest:request];
[direction calculateDirectionsWithCompletionHandler: ^(MKDirectionsResponse *response, NSError *error) {
if (error) {
NSLog(@"Error is %@",error);
}
else {
MKRoute *route = [response.routes firstObject];
NSUInteger pointCount = route.polyline.pointCount;
//Allocate a C array to hold this many points/coordinates...
CLLocationCoordinate2D *routeCoordinates = malloc(pointCount * sizeof(CLLocationCoordinate2D));
//Get the coordinates (all of them)...
[route.polyline getCoordinates:routeCoordinates range:NSMakeRange(0, pointCount)];
NSMutableArray *locationsArray = [[NSMutableArray alloc] init];
CLLocation *lastLocation = [[CLLocation alloc] init];
//Call snap to road with 100 locations at a time
for (int start = 0; start < pointCount; start += 99) {
[locationsArray removeAllObjects];
NSInteger length = MIN(99, pointCount-start);
if(start != 0){
[locationsArray addObject:lastLocation];
}
for(int i = start;i<start+length;i++){
CLLocationCoordinate2D loc2D = routeCoordinates[i];
CLLocation *location = [[CLLocation alloc] initWithLatitude:loc2D.latitude longitude:loc2D.longitude];
[locationsArray addObject:location];
}
lastLocation = [locationsArray lastObject];
[self snapPathToRoad:locationsArray];
}
//Free the memory used by the C array
free(routeCoordinates);
}
}];
}
-(void)snapPathToRoad:(NSMutableArray*)passedInArray{
//Create string to store coordinates in for the URL
NSString *tempcoordinatesForURL = @"";
//Append tempcoordinatesForURL string by the coordinates in the right format
for(int i = 0;i<[passedInArray count];i++){
CLLocationCoordinate2D coordinates = [[passedInArray objectAtIndex:i] coordinate];
NSString *coordinatesString = [NSString stringWithFormat:@"|%f,%f|",coordinates.latitude,coordinates.longitude];
tempcoordinatesForURL = [tempcoordinatesForURL stringByAppendingString:coordinatesString];
}
//Remove unnecessary charchters from tempcoordinatesForURL
NSString *coordinatesForURL = [[tempcoordinatesForURL substringToIndex:[tempcoordinatesForURL length]-1] stringByReplacingOccurrencesOfString:@"||" withString:@"|"];
//Create url by removing last charachter from coordinatesForURL string
NSString *urlPath = [NSString stringWithFormat:@"https://roads.googleapis.com/v1/snapToRoads?path=%@&interpolate=true&key=AIzaSyDrtHA-AMiVVylUPcp46_Vf1eZJJFBwRCY",[coordinatesForURL substringFromIndex:1]];
//Remove unsupproted charchters from urlPath and create an NSURL
NSString *escapedUrlPath = [urlPath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSURL *url = [NSURL URLWithString:escapedUrlPath];
//Create request
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//Send request to server
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
//If response, parse JSON
if(response){
//Dictionary with the whole JSON file
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
//Array of snapped points from the JSON
NSArray *snappedPoints = [result objectForKey:@"snappedPoints"];
//Loop through the snapped points array and add each coordinate to the path
for (int i = 0; i<[snappedPoints count]; i++) {
NSDictionary *location = [[snappedPoints objectAtIndex:i] objectForKey:@"location"];
double latitude = [[location objectForKey:@"latitude"] doubleValue];
double longitude = [[location objectForKey:@"longitude"] doubleValue];
[pathToDraw addCoordinate:CLLocationCoordinate2DMake(latitude, longitude)];
}
//As this method is called multiple times, clear the previous polylines so only the final one will be visible on the map
[self.mapView clear];
//Draw polyline with path
GMSPolyline *polyline = [GMSPolyline polylineWithPath:pathToDraw];
polyline.map = self.mapView;
polyline.strokeColor = [UIColor darkGrayColor];
polyline.strokeWidth = 6;
}
//If error, log it
else if(connectionError){
NSLog(@"%@",connectionError);
}
}];
}
"patToDraw
是 GMSMutablePath
ivar"
最终,我找到了问题所在。
如果异步调用多个请求,并非所有请求都会同时完成。因为它们中的每一个都将坐标添加到相同的路径,所以例如坐标较少的请求将更快完成,尽管它们被调用得较晚。这导致以错误的顺序添加到路径的坐标。
我知道如何使用 snap to road API 并解析响应,将其显示在地图上等。但是,snap to road API 有 100 的限制 coordinates/request.
假设我有一个包含 100 多个坐标的数组,并希望所有坐标都与道路对齐。
道路捕捉 API docs 描述了处理超过 100 个坐标时的解决方法,但它是 Java 代码(我认为)而且我真的不知道明白它。
我怎么能在 Objective-C 中做到这一点?
在我的实现中,我通过从我的数组中获取 100 个坐标的范围多次调用道路捕捉 api。然而,当在地图上绘制时,这会导致奇怪的多段线:
这是我的代码:
-(void)getDirectionsFrom:(CLLocation*)startLocation to:(CLLocation*)endLocation{
//Create placemarks from the passed in locations
MKPlacemark *start = [[MKPlacemark alloc] initWithCoordinate:locManager.location.coordinate addressDictionary:NULL];
MKPlacemark *finsih = [[MKPlacemark alloc] initWithCoordinate:endLocation.coordinate addressDictionary:NULL];
//Create direction request
MKDirectionsRequest *request = [[MKDirectionsRequest alloc]init];
[request setSource:[[MKMapItem alloc] initWithPlacemark:start]];
[request setDestination:[[MKMapItem alloc] initWithPlacemark:finsih]];
[request setTransportType:MKDirectionsTransportTypeAutomobile];
//Calculate directions
MKDirections *direction = [[MKDirections alloc]initWithRequest:request];
[direction calculateDirectionsWithCompletionHandler: ^(MKDirectionsResponse *response, NSError *error) {
if (error) {
NSLog(@"Error is %@",error);
}
else {
MKRoute *route = [response.routes firstObject];
NSUInteger pointCount = route.polyline.pointCount;
//Allocate a C array to hold this many points/coordinates...
CLLocationCoordinate2D *routeCoordinates = malloc(pointCount * sizeof(CLLocationCoordinate2D));
//Get the coordinates (all of them)...
[route.polyline getCoordinates:routeCoordinates range:NSMakeRange(0, pointCount)];
NSMutableArray *locationsArray = [[NSMutableArray alloc] init];
CLLocation *lastLocation = [[CLLocation alloc] init];
//Call snap to road with 100 locations at a time
for (int start = 0; start < pointCount; start += 99) {
[locationsArray removeAllObjects];
NSInteger length = MIN(99, pointCount-start);
if(start != 0){
[locationsArray addObject:lastLocation];
}
for(int i = start;i<start+length;i++){
CLLocationCoordinate2D loc2D = routeCoordinates[i];
CLLocation *location = [[CLLocation alloc] initWithLatitude:loc2D.latitude longitude:loc2D.longitude];
[locationsArray addObject:location];
}
lastLocation = [locationsArray lastObject];
[self snapPathToRoad:locationsArray];
}
//Free the memory used by the C array
free(routeCoordinates);
}
}];
}
-(void)snapPathToRoad:(NSMutableArray*)passedInArray{
//Create string to store coordinates in for the URL
NSString *tempcoordinatesForURL = @"";
//Append tempcoordinatesForURL string by the coordinates in the right format
for(int i = 0;i<[passedInArray count];i++){
CLLocationCoordinate2D coordinates = [[passedInArray objectAtIndex:i] coordinate];
NSString *coordinatesString = [NSString stringWithFormat:@"|%f,%f|",coordinates.latitude,coordinates.longitude];
tempcoordinatesForURL = [tempcoordinatesForURL stringByAppendingString:coordinatesString];
}
//Remove unnecessary charchters from tempcoordinatesForURL
NSString *coordinatesForURL = [[tempcoordinatesForURL substringToIndex:[tempcoordinatesForURL length]-1] stringByReplacingOccurrencesOfString:@"||" withString:@"|"];
//Create url by removing last charachter from coordinatesForURL string
NSString *urlPath = [NSString stringWithFormat:@"https://roads.googleapis.com/v1/snapToRoads?path=%@&interpolate=true&key=AIzaSyDrtHA-AMiVVylUPcp46_Vf1eZJJFBwRCY",[coordinatesForURL substringFromIndex:1]];
//Remove unsupproted charchters from urlPath and create an NSURL
NSString *escapedUrlPath = [urlPath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSURL *url = [NSURL URLWithString:escapedUrlPath];
//Create request
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//Send request to server
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
//If response, parse JSON
if(response){
//Dictionary with the whole JSON file
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
//Array of snapped points from the JSON
NSArray *snappedPoints = [result objectForKey:@"snappedPoints"];
//Loop through the snapped points array and add each coordinate to the path
for (int i = 0; i<[snappedPoints count]; i++) {
NSDictionary *location = [[snappedPoints objectAtIndex:i] objectForKey:@"location"];
double latitude = [[location objectForKey:@"latitude"] doubleValue];
double longitude = [[location objectForKey:@"longitude"] doubleValue];
[pathToDraw addCoordinate:CLLocationCoordinate2DMake(latitude, longitude)];
}
//As this method is called multiple times, clear the previous polylines so only the final one will be visible on the map
[self.mapView clear];
//Draw polyline with path
GMSPolyline *polyline = [GMSPolyline polylineWithPath:pathToDraw];
polyline.map = self.mapView;
polyline.strokeColor = [UIColor darkGrayColor];
polyline.strokeWidth = 6;
}
//If error, log it
else if(connectionError){
NSLog(@"%@",connectionError);
}
}];
}
"patToDraw
是 GMSMutablePath
ivar"
最终,我找到了问题所在。
如果异步调用多个请求,并非所有请求都会同时完成。因为它们中的每一个都将坐标添加到相同的路径,所以例如坐标较少的请求将更快完成,尽管它们被调用得较晚。这导致以错误的顺序添加到路径的坐标。