4

I'm using this code to connect pins(points on map) with polyline:

CLLocationCoordinate2D coordinates[allLocations.count];
    int i = 0;
    for (locHolder *location in allLocations) {
        coordinates[i] = CLLocationCoordinate2DMake([location.lat floatValue], [location floatValue]);
        i++;
    }
    MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coordinates count:[allLocations count]];
    self->polyline = polyline;
    [self.mapView addOverlay:self->polyline level:MKOverlayLevelAboveRoads];

But this code connects them over-the-air(ignoring roads), is it possible to connect multiple CLLocationCoordinate2D locations with polyline that follows roads?

** And a shor sub question, Is there any difference in performance between [allLocations count] and allLocations.count.

Thanks.

user2570174
  • 601
  • 1
  • 6
  • 9
  • 1
    Use MKDirectionsRequest to get the driving route between the locations. See http://stackoverflow.com/questions/18805613/display-route-on-ios-7-maps-addoverlay-has-no-effect for an example. Also, `[allLocations count]` and `allLocations.count` are exactly the same (see http://stackoverflow.com/questions/1249392/style-dot-notation-vs-message-notation-in-objective-c-2-0). –  May 08 '14 at 02:07
  • I have already looked into MKDirectionsRequest, but it allows to connect points A and B, but what I need is connecting points A and X throught B,C,D,E... Can that even be acheved? – user2570174 May 08 '14 at 08:57
  • 1
    Call it for A to B, then for B to C, then... –  May 08 '14 at 10:53

1 Answers1

4

In these days I've came across with the same problem, and looking for answers here and there, I found this answer from Rob very useful for this case.

First, supose you have in your MapViewController, an array of objects containing an origin an a destination, each one being of type CLLocationCoordinate2D

In your MapViewController.h

@property (nonatomic, strong) NSArray *locations;

Then, in the implementation, populate that array with some data that goes like this:

_locations = [NSArray arrayWithObjects:
    [RouteObject routeWithOrigin:CLLocationCoordinate2DMake(-23.595571, -46.684408) destination:CLLocationCoordinate2DMake(-23.597886, -46.673950)],
    [RouteObject routeWithOrigin:CLLocationCoordinate2DMake(-23.597886, -46.673950) destination:CLLocationCoordinate2DMake(-23.597591, -46.666805)],
    [RouteObject routeWithOrigin:CLLocationCoordinate2DMake(-23.597591, -46.666805) destination:CLLocationCoordinate2DMake(-23.604061, -46.662728)], nil];

Now that you have your array of origin and destinations, you can start drawing a route between them (from A to B, from B to C and from C to D).

Add a button and then connect an IBAction so in that method you are going to do de magic.

- (IBAction)btnDirectionsPressed:(id)sender {
    [self enableUI:NO];    // This method enables or disables all the UI elements that interact with the user

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);     // Create the semaphore    

    __block NSMutableArray *routes = [[NSMutableArray alloc] init];         // Arrays to store MKRoute objects and MKAnnotationPoint objects, so then we can draw them on the map
    __block NSMutableArray *annotations = [[NSMutableArray alloc] init];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        for (RouteObject *routeObject in _locations) {
            MKDirectionsRequest *directionsRequest = [MKDirectionsRequest new];
            [directionsRequest setTransportType:MKDirectionsTransportTypeAutomobile];
            [directionsRequest setSource:[routeObject originMapItem]];
            [directionsRequest setDestination:[routeObject destinationMapItem]];
            [directionsRequest setRequestsAlternateRoutes:NO];

            MKDirections *direction = [[MKDirections alloc] initWithRequest:directionsRequest];

            // For each object in the locations array, we request that route from its origin and its destination
            [direction calculateDirectionsWithCompletionHandler: ^(MKDirectionsResponse *response, NSError *error) {   
                if (error) {
                    NSLog(@"There was an error getting your directions");
                    return;
                }

                MKRoute *route = [response.routes firstObject];   
                [routes addObject:route];
                [annotations addObject:[routeObject destinationAnnotation]];

                dispatch_semaphore_signal(semaphore);    // Send the signal that one semaphore is ready to consume
            }];
        }
    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        for (int i = 0; i < _locations.count; i++) {
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);    // Wait until one semaphore is ready to consume

            dispatch_async(dispatch_get_main_queue(), ^{    // For each element, dispatch to the main queue to draw route and annotation corresponding to that location
                MKRoute *route = routes[i];
                [self.mapView addOverlay:route.polyline];
                [self.mapView addAnnotation:annotations[i]];
            });
        }

        dispatch_async(dispatch_get_main_queue(), ^{   // Finally, dispatch to the main queue enabling elements and resizing map to show all the annotations
            [self enableUI:YES];
            [self fitRegionToRoutes];
        });
    });
}

Hope this help!

Joel.

Community
  • 1
  • 1
Joel Márquez
  • 419
  • 5
  • 8
  • Hi, I am working on iOS after years of gap. trying to run this code and it gives error as 'use of undeclared identifire RouteObject'. I have included Mapkit and CoreLocation framework and imported in file. Please suggest. I wanted to create a find out distance between multiple points other than start and destination. – Pawriwes Apr 21 '15 at 16:41
  • @Pawriwes RouteObject is some POJO that I made for this purpose. It has two properties, both of type CLLocationCoordinate2D, and some useful methods. – Joel Márquez Jul 10 '15 at 14:42