Ala*_*ore 45 iphone json objective-c google-directions-api google-polyline
我想在地图上绘制与我通过Google Directions API获得的路线JSON相对应的路线:http://code.google.com/apis/maps/documentation/directions/
我已经想出如何从阶段字段中提取纬度和经度,但这并不能很好地遵循弯曲的道路.我认为我需要的是解码折线信息,我找到了关于如何编码折线的Googles说明:http://code.google.com/apis/maps/documentation/utilities/polylinealgorithm.html
我确实在这里找到了一些代码用于Android以及解码折线的Javascript,例如:
使用Google Directions API地图查看绘制路线 - 解码折线
但是对于Objective-C iPhone代码我找不到相同的内容,任何人都可以帮我这个吗?我敢肯定,如果必须的话,我可以自己做,但如果它已经可以在某个地方使用,那肯定能节省我一些时间...
编辑:这里的关键是能够逐个字符地解码base64编码.更具体地说,我在谷歌的JSON中得到了类似的东西,它使用base64编码进行编码:
... "overview_polyline" : {
"points" : "ydelDz~vpN_@NO@QEKWIYIIO?YCS@WFGBEBICCAE?G@y@RKBEBEBAD?HTpB@LALALCNEJEFSP_@LyDv@aB\\GBMB"
},
...
Run Code Online (Sandbox Code Playgroud)
注意:我应该提一下,这个问题是指Google Maps API v1,使用GMSPolyLine polyLineWithPath在v2中更容易实现,因为下面的许多答案都会告诉你(感谢@cdescours).
Sed*_*ien 85
如果它与问题相关,我希望链接到我自己的博客文章并不违反规则,但我过去已经解决了这个问题.链接帖子的独立答案:
@implementation MKPolyline (MKPolyline_EncodedString)
+ (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;
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;
}
@end
Run Code Online (Sandbox Code Playgroud)
cde*_*urs 31
最好和最轻的答案应该是使用Google在框架中提供的方法:
[GMSPolyline polylineWithPath:[GMSPath pathFromEncodedPath:encodedPath]]
Roo*_*ode 10
如果您正在iOS上使用谷歌地图并希望绘制包含折线的路线,谷歌本身提供了一种更简单的方法来从折线获取GMSPath,
GMSPath *pathFromPolyline = [GMSPath pathFromEncodedPath:polyLinePoints];
Run Code Online (Sandbox Code Playgroud)
这是完整的代码:
+ (void)callGoogleServiceToGetRouteDataFromSource:(CLLocation *)sourceLocation toDestination:(CLLocation *)destinationLocation onMap:(GMSMapView *)mapView_{
NSString *baseUrl = [NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%f,%f&sensor=false", sourceLocation.coordinate.latitude, sourceLocation.coordinate.longitude, destinationLocation.coordinate.latitude, destinationLocation.coordinate.longitude];
NSURL *url = [NSURL URLWithString:[baseUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSLog(@"Url: %@", url);
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
GMSMutablePath *path = [GMSMutablePath path];
NSError *error = nil;
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
NSArray *routes = [result objectForKey:@"routes"];
NSDictionary *firstRoute = [routes objectAtIndex:0];
NSDictionary *leg = [[firstRoute objectForKey:@"legs"] objectAtIndex:0];
NSArray *steps = [leg objectForKey:@"steps"];
int stepIndex = 0;
CLLocationCoordinate2D stepCoordinates[1 + [steps count] + 1];
for (NSDictionary *step in steps) {
NSDictionary *start_location = [step objectForKey:@"start_location"];
stepCoordinates[++stepIndex] = [self coordinateWithLocation:start_location];
[path addCoordinate:[self coordinateWithLocation:start_location]];
NSString *polyLinePoints = [[step objectForKey:@"polyline"] objectForKey:@"points"];
GMSPath *polyLinePath = [GMSPath pathFromEncodedPath:polyLinePoints];
for (int p=0; p<polyLinePath.count; p++) {
[path addCoordinate:[polyLinePath coordinateAtIndex:p]];
}
if ([steps count] == stepIndex){
NSDictionary *end_location = [step objectForKey:@"end_location"];
stepCoordinates[++stepIndex] = [self coordinateWithLocation:end_location];
[path addCoordinate:[self coordinateWithLocation:end_location]];
}
}
GMSPolyline *polyline = nil;
polyline = [GMSPolyline polylineWithPath:path];
polyline.strokeColor = [UIColor grayColor];
polyline.strokeWidth = 3.f;
polyline.map = mapView_;
}];
}
+ (CLLocationCoordinate2D)coordinateWithLocation:(NSDictionary*)location
{
double latitude = [[location objectForKey:@"lat"] doubleValue];
double longitude = [[location objectForKey:@"lng"] doubleValue];
return CLLocationCoordinate2DMake(latitude, longitude);
}
Run Code Online (Sandbox Code Playgroud)
斯威夫特 3.0
let polyline = GMSPolyline(path: GMSPath.init(fromEncodedPath: encodedPolyline))
Run Code Online (Sandbox Code Playgroud)
这不是 Objective-C 中的内容,但如果您想从 Google 地图中解码折线字符串,那么 Google 会将您带到这个线程。如果其他人需要它(就像我一样),这里有一个用于解码折线字符串的 Python 实现。这是从 Mapbox JavaScript 版本移植的;在我的回购页面上找到更多信息。
def decode_polyline(polyline_str):
index, lat, lng = 0, 0, 0
coordinates = []
changes = {'latitude': 0, 'longitude': 0}
# Coordinates have variable length when encoded, so just keep
# track of whether we've hit the end of the string. In each
# while loop iteration, a single coordinate is decoded.
while index < len(polyline_str):
# Gather lat/lon changes, store them in a dictionary to apply them later
for unit in ['latitude', 'longitude']:
shift, result = 0, 0
while True:
byte = ord(polyline_str[index]) - 63
index+=1
result |= (byte & 0x1f) << shift
shift += 5
if not byte >= 0x20:
break
if (result & 1):
changes[unit] = ~(result >> 1)
else:
changes[unit] = (result >> 1)
lat += changes['latitude']
lng += changes['longitude']
coordinates.append((lat / 100000.0, lng / 100000.0))
return coordinates
Run Code Online (Sandbox Code Playgroud)
- (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;
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;
}
- (MKPolygonRenderer *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
// MKPolygonRenderer *polylineView = [[MKPolygonRenderer alloc] initWithOverlay:overlay];
MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
polylineView.strokeColor = [UIColor redColor];
polylineView.lineWidth = 4.0;
[self zoomToPolyLine:mapview polyline:overlay animated:YES];
return polylineView;
}
-(void)zoomToPolyLine: (MKMapView*)map polyline: (MKPolyline*)polyline animated: (BOOL)animated
{
[map setVisibleMapRect:[polyline boundingMapRect] edgePadding:UIEdgeInsetsMake(25.0, 25.0, 25.0, 25.0) animated:animated];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
// NSLog(@"didUpdateToLocation: %@", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
currlong = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.longitude];
currlt = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.latitude];
}
NSString *origin = [NSString stringWithFormat:@"%@%@%@",currlt,@",",currlong];
//I have just mention static location
NSString *drivein = @"23.0472963,72.52757040000006";
NSString *apikey = [NSString stringWithFormat:@"https://maps.googleapis.com/maps/api/directions/json?origin=%@&destination=%@",origin,drivein];
NSURL *url = [NSURL URLWithString:apikey];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLResponse *response;
NSError *error;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
if(!error)
{
NSData *data = [responseString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error];
NSArray *routesArray = [jsonResponse objectForKey:@"routes"];
NSLog(@"route array %@",routesArray);
if ([routesArray count] > 0)
{
NSDictionary *routeDict = [routesArray objectAtIndex:0];
NSDictionary *routeOverviewPolyline = [routeDict objectForKey:@"overview_polyline"];
NSString *points = [routeOverviewPolyline objectForKey:@"points"];
MKPolyline *line = [self polylineWithEncodedString:points];
[mapview addOverlay:line];
}
}
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(currentLocation.coordinate, 500, 500);
MKCoordinateRegion adjustedRegion = [mapview regionThatFits:viewRegion];
[mapview setRegion:adjustedRegion animated:YES];
mapview.showsUserLocation = YES;
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = currentLocation.coordinate;
point.title = @"Your current Locations";
point.subtitle = @"You are here!";
[mapview addAnnotation:point];
[locationmanger stopUpdatingLocation];
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
43969 次 |
最近记录: |