使用 Google Maps iOS 绘制路线方向
Posted
技术标签:
【中文标题】使用 Google Maps iOS 绘制路线方向【英文标题】:Draw route directions using Google Maps iOS 【发布时间】:2014-08-09 15:05:49 【问题描述】:我得到一个到自定义位置的GMSPolyline
,但我没有得到从用户位置到某个自定义位置的路线方向 (GMSPolyline
)。
我所做的是放置一个GMSMapView
并保留核心位置。我正在更新核心位置委托方法 (locationManager: didUpdateLocations:
) 中的路线。
我想使用适用于 ios SDK 的 Google Maps,因为 Apple Maps 在我需要的国家/地区没有路线。我的代码如下:
- (void)viewDidLoad
[super viewDidLoad];
waypointStrings_ = [[NSMutableArray alloc]init];
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:self.latitude longitude:self.longitude zoom:13];
mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera];
mapView_.myLocationEnabled = YES;
self.view = mapView_;
CLLocationManager *locManager = [[CLLocationManager alloc] init];
if ( [CLLocationManager locationServicesEnabled] )
[locManager setDelegate:self];
[locManager setDesiredAccuracy:kCLLocationAccuracyBest];
[locManager startUpdatingLocation];
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
CLLocationCoordinate2D userCoordinate = [[locations lastObject] coordinate];
GMSMarker *marker = [GMSMarker markerWithPosition:CLLocationCoordinate2DMake(self.latitude,self.longitude)];
marker.map = mapView_;
NSString *majlisPositionString = [[NSString alloc] initWithFormat:@"%f,%f", self.latitude,self.longitude];
[waypointStrings_ addObject:majlisPositionString];
GMSMarker *userMarker = [GMSMarker markerWithPosition:CLLocationCoordinate2DMake(userCoordinate.latitude, userCoordinate.longitude)];
userMarker.map = mapView_;
NSString *userPositionString = [[NSString alloc] initWithFormat:@"%f,%f", userCoordinate.latitude, userCoordinate.longitude];
[waypointStrings_ addObject:userPositionString];
NSString *sensor = @"false";
NSArray *parameters = [NSArray arrayWithObjects:sensor, waypointStrings_, nil];
NSArray *keys = [NSArray arrayWithObjects:@"sensor", @"waypoints", nil];
NSDictionary *query = [NSDictionary dictionaryWithObjects:parameters forKeys:keys];
MDDirectionService *mds=[[MDDirectionService alloc] init];
SEL selector = @selector(addDirections:);
[mds setDirectionsQuery:query withSelector:selector withDelegate:self];
- (void)addDirections:(NSDictionary *)json
NSDictionary *routes = [json objectForKey:@"routes"][0];
NSDictionary *route = [routes objectForKey:@"overview_polyline"];
NSString *overview_route = [route objectForKey:@"points"];
GMSPath *path = [GMSPath pathFromEncodedPath:overview_route];
GMSPolyline *polyline = [GMSPolyline polylineWithPath:path];
polyline.map = mapView_;
【问题讨论】:
试试这个链接:-***.com/questions/20956793/… 【参考方案1】:-(void)LoadMapRoute:(NSString*)SourceAddress andDestinationAddress:(NSString*)DestinationAdds
NSString *strUrl;
strUrl= [NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/directions/json?origin=%@&destination=%@&sensor=false",SourceAddress,DestinationAdds];
strUrl=[strUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSData *data =[NSData dataWithContentsOfURL:[NSURL URLWithString:strUrl]];
NSError* error;
if (data)
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:data //1
options:kNilOptions
error:&error];
NSArray *arrRouts=[json objectForKey:@"routes"];
if ([arrRouts isKindOfClass:[NSArray class]]&&arrRouts.count==0)
[self zoomToFitMapAnnotations:self.mapView];
return;
CLLocationCoordinate2D coordinates[2];
coordinates[0].latitude = [[CommonUtils checkNullString:[AppDelegate getAppDelegate].strLatitude] doubleValue];Current loaction latitude.
coordinates[0].longitude = [[CommonUtils checkNullString:[AppDelegate getAppDelegate].strLongitude] doubleValue];//Current loaction longitude.
coordinates[1].latitude = [[CommonUtils checkNullString:latitute] doubleValue];
coordinates[1].longitude = [[CommonUtils checkNullString:longitude] doubleValue];
if (CLLocationCoordinate2DIsValid(coordinates[1]) && CLLocationCoordinate2DIsValid(coordinates[0]))
//NSLog(@"Coordinate valid");
self.mapView.delegate=self;
CLLocation *location1 = [[CLLocation alloc] initWithLatitude:coordinates[0].latitude longitude:coordinates[0].longitude];
CLLocation *location2 = [[CLLocation alloc] initWithLatitude:coordinates[1].latitude longitude:coordinates[1].longitude];
CLLocationDistance kilometers = [location1 distanceFromLocation:location2] / 1000;
//NSLog(@"%f",kilometers);
self.lblRideViewkilometer.text=[NSString stringWithFormat:@"%f KM",kilometers];
// //NSLog(@"Distance i meters: %f", [location1 distanceFromLocation:location2]);
// self.polyline = [MKPolyline polylineWithCoordinates:coordinates count:2];
// [self.mapView setVisibleMapRect:[self.polyline boundingMapRect]];
//
//
// //If you want the route to be visible
// [self.mapView addOverlay:self.polyline];
else
//NSLog(@"Coordinate invalid");
NSArray* arrpolyline = [[[json valueForKeyPath:@"routes.legs.steps.polyline.points"] objectAtIndex:0] objectAtIndex:0]; //2
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];
double destLat=[[[[json valueForKeyPath:@"routes.legs.end_location.lat"] objectAtIndex:0] objectAtIndex:0] doubleValue];
double destLong=[[[[json valueForKeyPath:@"routes.legs.end_location.lng"] objectAtIndex:0] objectAtIndex:0] doubleValue];
CLLocationCoordinate2D sourceCordinate = CLLocationCoordinate2DMake(srcLat, srcLong);
CLLocationCoordinate2D destCordinate = CLLocationCoordinate2DMake(destLat, destLong);
[self addAnnotationSrcAndDestination:sourceCordinate :destCordinate andAdds:nil andDestinationAddress:DestinationAdds];
// NSArray *steps=[[aary objectAtIndex:0]valueForKey:@"steps"];
// replace lines with this may work
polyLinesArray =[[NSMutableArray alloc]initWithCapacity:0];
for (int i = 0; i < [arrpolyline count]; i++)
NSString* encodedPoints = [arrpolyline objectAtIndex:i] ;
MKPolyline *route = [self polylineWithEncodedString:encodedPoints];
[polyLinesArray addObject:route];
self.polyline = [MKPolyline polylineWithCoordinates:coordinates count:2];
[self.mapView setVisibleMapRect:[self.polyline boundingMapRect]];
[self.mapView addOverlays:polyLinesArray];
self.mapView.delegate = self;
[self zoomToFitMapAnnotations:self.mapView];
else
// [self.btnDirection setEnabled:NO];
// [self ShowAlert:@"didn't find direction"];
-(void)addAnnotationSrcAndDestination :(CLLocationCoordinate2D )srcCord :(CLLocationCoordinate2D)destCord andAdds:(NSString*)SourceAddress andDestinationAddress:(NSString*)DestinationAdds
MKPointAnnotation *sourceAnnotation = [[MKPointAnnotation alloc]init];
destAnnotation = [[MKPointAnnotation alloc]init];
sourceAnnotation.coordinate=srcCord;
destAnnotation.coordinate=destCord;
sourceAnnotation.title=SourceAddress;
CLLocation *LocationAtual = [[CLLocation alloc] initWithLatitude:destCord.latitude longitude:destCord.longitude];
CLGeocoder *geocoder = [[CLGeocoder alloc] init] ;
[geocoder reverseGeocodeLocation:LocationAtual
completionHandler:^(NSArray *placemarks, NSError *error)
if (error)
//NSLog(@"Geocode failed with error: %@", error);
return;
CLPlacemark *placemark = [placemarks objectAtIndex:0];
//NSLog(@"placemark.ISOcountryCode %@",placemark.ISOcountryCode);
//NSLog(@"locality %@",placemark.subLocality);
//NSLog(@"postalCode %@",placemark.postalCode);
destAnnotation.title=[NSString stringWithFormat:@"%@ %@ ",placemark.name,placemark.locality];
// [self.mapView.userLocation setTitle:[NSString stringWithFormat:@"%@ %@ ",placemark.name,placemark.locality]];
];
// destAnnotation.title=DestinationAdds;
//destAnnotation.title=[NSString stringWithFormat:@"%@,%@,%@",[self.dictRetailerInfo objectForKey:@"street_address1"],[self.dictRetailerInfo objectForKey:@"city"],[self.dictRetailerInfo objectForKey:@"country"]];
// destAnnotation.title=nil;
[self.mapView addAnnotation:sourceAnnotation];
[self.mapView addAnnotation:destAnnotation];
- (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;
-(void)zoomToFitMapAnnotations:(MKMapView*)aMapView
if([aMapView.annotations count] == 0)
return;
CLLocationCoordinate2D topLeftCoord;
topLeftCoord.latitude = -90;
topLeftCoord.longitude = 180;
CLLocationCoordinate2D bottomRightCoord;
bottomRightCoord.latitude = 90;
bottomRightCoord.longitude = -180;
for(MKPointAnnotation *annotation in self.mapView.annotations)
if (![[annotation class] isEqual:[MKUserLocation class]])
topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude);
topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude);
bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude);
bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.coordinate.latitude);
MKCoordinateRegion region;
region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5;
region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5;
region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; // Add a little extra space on the sides
region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1; // Add a little extra space on the sides
region = [aMapView regionThatFits:region];
[self.mapView setRegion:region animated:YES];
mapZoom=YES;
//- (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views
//
// MKMapRect zoomRect = MKMapRectNull;
// for (id <MKAnnotation> annotation in mv.annotations)
//
// MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
// MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
// zoomRect = MKMapRectUnion(zoomRect, pointRect);
//
// [mv setVisibleMapRect:zoomRect animated:YES];
//
- (void)moveMapToLocation:(CLLocation*)tmpLocation
CLLocationDistance visibleDistance = 1000; // 1 kilometers
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(tmpLocation.coordinate, visibleDistance, visibleDistance);
MKCoordinateRegion adjustedRegion = [self.mapView regionThatFits:viewRegion];
[self.mapView setRegion:adjustedRegion animated:YES];
【讨论】:
【参考方案2】:var arrayPolyline = [GMSPolyline]()
var selectedRought:String!
func LoadMapRoute1()
let strUrl:String = "https://maps.googleapis.com/maps/api/directions/json?sensor=false&mode=driving&alternatives=true&origin=\(self.source.latitude),\(self.source.longitude)&destination=\(self.destination.latitude),\(self.destination.longitude)"
let escapedString = strUrl.replacingOccurrences(of: " ", with: "")
let url = URL(string: escapedString)
URLSession.shared.dataTask(with: url!, completionHandler:
(data, response, error) in
if(error != nil)
print("error")
else
do
let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String : AnyObject]
let arrRouts = json["routes"] as! NSArray
for polyline in self.arrayPolyline
polyline.map = nil;
self.arrayPolyline.removeAll()
let pathForRought:GMSMutablePath = GMSMutablePath()
if (arrRouts.count == 0)
let distance:CLLocationDistance = CLLocation.init(latitude: self.source.latitude, longitude: self.source.longitude).distance(from: CLLocation.init(latitude: self.destination.latitude, longitude: self.destination.longitude))
pathForRought.add(self.source)
pathForRought.add(self.destination)
let polyline = GMSPolyline.init(path: pathForRought)
polyline.strokeWidth = 5
polyline.strokeColor = UIColor.blue
polyline.isTappable = true
self.arrayPolyline.append(polyline)
if (distance > 8000000)
polyline.geodesic = false
else
polyline.geodesic = true
polyline.map = self.mapView;
else
for (index, element) in arrRouts.enumerated()
let dicData:NSDictionary = element as! NSDictionary
let routeOverviewPolyline = dicData["overview_polyline"] as! NSDictionary
let path = GMSPath.init(fromEncodedPath: routeOverviewPolyline["points"] as! String)
let polyline = GMSPolyline.init(path: path)
polyline.isTappable = true
self.arrayPolyline.append(polyline)
polyline.strokeWidth = 5
if index == 0
polyline.strokeColor = UIColor.blue;
else
polyline.strokeColor = UIColor.darkGray;
polyline.geodesic = true;
for po in self.arrayPolyline.reversed()
po.map = self.mapView;
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5)
let bounds:GMSCoordinateBounds = GMSCoordinateBounds.init(path: GMSPath.init(fromEncodedPath: self.selectedRought)!)
self.mapView.animate(with: GMSCameraUpdate.fit(bounds))
catch let error as NSError
print("error:\(error)")
).resume()
【讨论】:
以上是关于使用 Google Maps iOS 绘制路线方向的主要内容,如果未能解决你的问题,请参考以下文章
将路线的 JSON 导入到 Google Maps Android 活动中
为 Google Maps API v2 Android 发布流媒体方向
如何在 Google Maps API 中的两个标记之间绘制路线?