顺利的MKPolyline跟随道路

时间:2015-04-29 05:59:38

标签: ios xcode swift mapkit mkpolyline

我知道几年前就已经问过这个问题,但所有答案都涉及使用Google Maps API来解决这个问题。我想知道是否有一个正确的方法可以解决这个问题,因为iOS8已经出局了,它为原生MapKit带来了许多改进。

基本上我在路上画了一条折线,它由许多中间点组成。

    var locations = [CLLocation]()
    for item in list {
        locations.append(CLLocation(latitude: CLLocationDegrees(item["location"]["coordinate"]["x"].doubleValue), longitude: CLLocationDegrees(item["location"]["coordinate"]["y"].doubleValue)))
    }
    var coordinates = locations.map({(location: CLLocation!) -> CLLocationCoordinate2D in return location.coordinate})
    var polyline = MKPolyline(coordinates: &coordinates, count: locations.count)
    mapView.addOverlay(polyline)

地图上一次有5到30个点。当折线连接它们时,我或多或少地得到了旅行的公平表示。问题是:它不会坚持到路上。

enter image description here

所以我得到"粗糙"边缘不时。即使我使用的是Google Direction API,它也只限于8个方向点,并且基本上决定了如何从A点到B点,沿途绘制平滑折线。此外,Directions API限制为每24小时2500次使用。我需要做的就是将我当前的折线调整到最近的道路

非常感谢

2 个答案:

答案 0 :(得分:1)

我使用递归块来获得72分的路线。总是它工作到50请求然后api抛出我的错误。我猜50是一分钟的限制。 50后我必须等待一段时间才能完成api工作。

我使用谷歌地图绘制折线。所以下面的代码采用lat,long数组并获取方向并将路径转换为一组点并在Google地图上呈现。

// Pathstr是|分离 //如果需要改进,请告诉我。 //我正在使用递归块,因为错误计算可能会在计算方向时产生错误,因此将其作为使用递归的顺序块。

NSArray *arr = [pathStr componentsSeparatedByString:@"|"];
    int pointsCount = (int)[arr count];
    NSMutableArray* pointsToUse = [[NSMutableArray alloc] init];

    for(NSString* locationStr in arr)
    {
        NSArray *locArr = [locationStr componentsSeparatedByString:@","];

        CLLocation *trackLocation = [[CLLocation alloc] initWithLatitude:[[locArr objectAtIndex:0] doubleValue] longitude:[[locArr objectAtIndex:1] doubleValue]];
        [pointsToUse addObject:trackLocation];
    }


    // __block declaration of the block makes it possible to call the block from within itself
    __block void (^urlFetchBlock)();


    __block int urlIndex = 0;

    // the 'recursive' block
    urlFetchBlock = [^void () {

        MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
        NSLog(@"Index Value:::%d", urlIndex);
        if(urlIndex < (pointsCount - 5))
        {
            MKPlacemark *sourcePlacemark = [[MKPlacemark alloc] initWithCoordinate:((CLLocation*)pointsToUse[urlIndex]).coordinate addressDictionary:nil];
            MKMapItem *sourceMapItem = [[MKMapItem alloc] initWithPlacemark:sourcePlacemark];
            [request setSource:sourceMapItem];

            MKPlacemark *destPlacemark = [[MKPlacemark alloc] initWithCoordinate:((CLLocation*)pointsToUse[urlIndex + 5]).coordinate addressDictionary:nil];
            MKMapItem *destMapItem = [[MKMapItem alloc] initWithPlacemark:destPlacemark];

            [request setDestination:destMapItem];
            //            NSLog(@"Source:%f ::%f, Dest: %f :: %f", ((CLLocation*)pointsToUse[i]).coordinate.latitude,((CLLocation*)pointsToUse[i]).coordinate.longitude, ((CLLocation*)pointsToUse[i+1]).coordinate.latitude, ((CLLocation*)pointsToUse[i+1]).coordinate.longitude);

            [request setTransportType:MKDirectionsTransportTypeAny];

            request.requestsAlternateRoutes = NO;

            MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
            [directions calculateDirectionsWithCompletionHandler:
             ^(MKDirectionsResponse *response, NSError *error) {
                 if (error) {
                     // Handle Error
                     NSLog(@"Error for this particular call");
                     urlIndex +=5;
                     urlFetchBlock();
                 } else {

                     for (MKRoute * route in response.routes) {

                         NSUInteger pointCount = route.polyline.pointCount;

                         NSLog(@"%lu", (unsigned long)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)];

                         GMSMutablePath *path = [GMSMutablePath path];

                         //this part just shows how to use the results...
                         for (int c=0; c < pointCount; c++)
                         {
                             [path addLatitude:routeCoordinates[c].latitude longitude:routeCoordinates[c].longitude];

                         }
                         GMSPolyline *polyline = [GMSPolyline polylineWithPath: path];

                         polyline.tappable  =  YES;
                         polyline.strokeWidth = width;

                         //                        polyline.strokeColor = [UIColor redColor];
                         polyline.geodesic = YES;
                         //    polyline.title = @"Driving route";
                         polyline.map = gMapView;
                         polyline.spans = @[[GMSStyleSpan spanWithColor:[UIColor redColor]]];
                     }
                     urlIndex +=5;
                     urlFetchBlock();

                 }
             }];

        }
    } copy];

    // initiate the url requests
    urlFetchBlock();

答案 1 :(得分:0)

我尝试了很多代码,最后我得到如下代码:

enter image description here

获取完整代码: https://github.com/javedmultani16/MapKitWithPolyLine

以下是同一代码:

  var locRoute : MKRoute?
    var directionsRequest = MKDirections.Request()
    var arrayPlacemarks = [MKMapItem]()

    var selectedPin:MKPlacemark? = nil
    let locationManager = CLLocationManager()

并在ViewDidLoad()上编写以下代码:

    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestWhenInUseAuthorization()
        locationManager.requestLocation()


        locationSearchTable.mapView = mapView
        mapView.delegate = self
    }

现在使用委托方法:


extension ViewController : MKMapViewDelegate {
    func mapView(_: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?{
        if annotation is MKUserLocation {
            //return nil so map view draws "blue dot" for standard user location

            //Add source location as user location
            let arrayPlacemarksource = MKPlacemark(coordinate: annotation.coordinate, addressDictionary: nil)
            arrayPlacemarks.append(MKMapItem(placemark: arrayPlacemarksource))
            return nil
        }
        let reuseId = "pin"
        var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
        pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
        pinView?.pinTintColor = UIColor.orange
        pinView?.canShowCallout = true
        let smallSquare = CGSize(width: 30, height: 30)
        let button = UIButton(frame: CGRect(origin: CGPoint(x: 0,y :0), size: smallSquare))
        button.setBackgroundImage(UIImage(named: "car"), for: .normal)
        button.addTarget(self, action: #selector(ViewController.getDirections), for: .touchUpInside)
        pinView?.leftCalloutAccessoryView = button
        return pinView
    }
    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        if overlay.isKind(of: MKPolyline.self){
                var polylineRenderer = MKPolylineRenderer(overlay: overlay)
                polylineRenderer.fillColor = UIColor.blue
                polylineRenderer.strokeColor = UIColor.blue
                polylineRenderer.lineWidth = 2

            return polylineRenderer
     }
        return MKOverlayRenderer(overlay: overlay)
    }

}

绘制折线,如下所示:


        //Add destination placemark...
        arrayPlacemarks.append(MKMapItem(placemark: placemark))

        directionsRequest.transportType = MKDirectionsTransportType.automobile

        //Draw polyline by using MKRoute so it follows the street roads...
        for (k, item) in arrayPlacemarks.enumerated() {
            if k < (arrayPlacemarks.count - 1) {
                directionsRequest.source = item
                directionsRequest.destination = arrayPlacemarks[k+1]

                let directions = MKDirections(request: directionsRequest)
          directions.calculate { (response:MKDirections.Response!, error: Error!) -> Void in
                    if error == nil {
                        self.locRoute = response.routes[0] as? MKRoute
                        let geodesic:MKPolyline = self.locRoute!.polyline
                        self.mapView.addOverlay(geodesic)
                    }
                }
            }
        }

        mapView.addAnnotation(annotation)
        let span = MKCoordinateSpan.init(latitudeDelta: 0.05, longitudeDelta: 0.05) //MKCoordinateSpanMake(0.05, 0.05)
        let region = MKCoordinateRegion.init(center: placemark.coordinate, span: span)
        mapView.setRegion(region, animated: true)