使用 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 中的两个标记之间绘制路线?

Google Maps v2 - 用不同颜色绘制路线 - Android

如何使用谷歌方向 API 在苹果地图上快速绘制路线?

Google Maps Roads API 返回重复的坐标和 placeIds