Smooth M.K. Poliline follows the road

I know this was asked a few years ago, but all the answers were related to using the Google Maps API to solve this problem. I wonder if there is a correct way to solve this now that iOS8 is disabled and has brought many improvements to its own MapKit.

Basically, I draw a polyline on the road, consisting of many intermediate points.

    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)

      

In due time on the map from 5 to 30 points. When the polyline connects them, I get a more or less fair view of the ride. The problem is, it does NOT stick to the road.

enter image description here

This way I get "rough" edges from time to time. Even if I use the Google Direction API, it is limited to 8 ways and basically decides how to get from point A to point B by drawing a smooth polyline along the way. Additionally, API Directions is capped at 2,500 custom per 24 hours. All I need to do is adjust my current polyline to the nearest road

Many thanks

+3


source to share


2 answers


After some digging, I was able to find the answer to this question, although I'm not entirely sure about its impact on the overall performance of whether Apple is happy as it ships a lot of little MKDirectionsRequest

's. For me, 30+ points is just fine.

    var myRoute : MKRoute?
    var directionsRequest = MKDirectionsRequest()
    var placemarks = [MKMapItem]()
    for item in list {
        var placemark = MKPlacemark(coordinate: CLLocationCoordinate2D(latitude: CLLocationDegrees(item["location"]["coordinate"]["x"].doubleValue), longitude: CLLocationDegrees(item["location"]["coordinate"]["y"].doubleValue)), addressDictionary: nil )
        placemarks.append(MKMapItem(placemark: placemark))
    }
    directionsRequest.transportType = MKDirectionsTransportType.Automobile
    for (k, item) in enumerate(placemarks) {
        if k < (placemarks.count - 1) {
            directionsRequest.setSource(item)
            directionsRequest.setDestination(placemarks[k+1])
            var directions = MKDirections(request: directionsRequest)
            directions.calculateDirectionsWithCompletionHandler { (response:MKDirectionsResponse!, error: NSError!) -> Void in
                if error == nil {
                    self.myRoute = response.routes[0] as? MKRoute
                    self.mapView.addOverlay(self.myRoute?.polyline)
                }
            }
        }
    }

      



Special thanks to Anna for pointing me in the right direction.

enter image description here

+6


source


I used a recursive block to get a 72 way route. always it works up to 50 requests, then the api throws me an error. I think 50 is the limit for a minute. after 50 I have to wait a while to get the api working.

I used google map to draw polyline. so the following code takes an array lat, long and gets the direction and transformation of the path to a set of points and rendering on a google map.



// Pathstr is | detached // Let me know if it needs improvement. // I use recursive blocks because the rendering can cause an error when calculating the direction, so if it's like a sequential block using recursive.

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


source







All Articles