Рисование маршрута в MapKit в iOS - PullRequest
54 голосов
/ 14 мая 2010

Я хочу нарисовать маршрут между двумя точками на карте. Что-то вроде гида. Когда турист нажимает на другое место, я хочу иметь возможность нарисовать маршрут; а также сообщить о расстоянии от текущего местоположения.

Мне известны сайты в Интернете, которые рассказывают, как рисовать полилинии на карте. Но большинство примеров содержало предварительно загруженный файл .csv с различными координатами.

Есть ли альтернативный способ получения координат от Google или любого другого провайдера, так как местоположение выбирается динамически.

Если НЕТ, как мне получить информацию для промежуточных координат?

Предлагает ли iOS 6 прямой способ решения этой проблемы?

Ответы [ 9 ]

61 голосов
/ 12 августа 2012

Следующие viewDidLoad будут (1) устанавливать два местоположения, (2) удалять все предыдущие аннотации и (3) вызывать пользовательские вспомогательные функции (чтобы получить точки маршрута и нарисовать маршрут).

-(void)viewDidLoad
{
    [super viewDidLoad];

    // Origin Location.
    CLLocationCoordinate2D loc1;
    loc1.latitude = 29.0167;
    loc1.longitude = 77.3833;
    Annotation *origin = [[Annotation alloc] initWithTitle:@"loc1" subTitle:@"Home1" andCoordinate:loc1];
    [objMapView addAnnotation:origin];

    // Destination Location.
    CLLocationCoordinate2D loc2;
    loc2.latitude = 19.076000;
    loc2.longitude = 72.877670;
    Annotation *destination = [[Annotation alloc] initWithTitle:@"loc2" subTitle:@"Home2" andCoordinate:loc2];
    [objMapView addAnnotation:destination];

    if(arrRoutePoints) // Remove all annotations
        [objMapView removeAnnotations:[objMapView annotations]];

    arrRoutePoints = [self getRoutePointFrom:origin to:destination];
    [self drawRoute];
    [self centerMap];
}

Ниже приведен метод MKMapViewDelegate, который рисует наложение (iOS 4.0 и более поздние версии).

/* MKMapViewDelegate Meth0d -- for viewForOverlay*/
- (MKOverlayView*)mapView:(MKMapView*)theMapView viewForOverlay:(id <MKOverlay>)overlay
{
    MKPolylineView *view = [[MKPolylineView alloc] initWithPolyline:objPolyline];
    view.fillColor = [UIColor blackColor];
    view.strokeColor = [UIColor blackColor];
    view.lineWidth = 4;
    return view;
}

Следующая функция получит оба местоположения и подготовит URL для получения всех точек маршрута. И, конечно, будет вызывать stringWithURL.

/* This will get the route coordinates from the Google API. */
- (NSArray*)getRoutePointFrom:(Annotation *)origin to:(Annotation *)destination
{
    NSString* saddr = [NSString stringWithFormat:@"%f,%f", origin.coordinate.latitude, origin.coordinate.longitude];
    NSString* daddr = [NSString stringWithFormat:@"%f,%f", destination.coordinate.latitude, destination.coordinate.longitude];

    NSString* apiUrlStr = [NSString stringWithFormat:@"http://maps.google.com/maps?output=dragdir&saddr=%@&daddr=%@", saddr, daddr];
    NSURL* apiUrl = [NSURL URLWithString:apiUrlStr];

    NSError *error;
    NSString *apiResponse = [NSString stringWithContentsOfURL:apiUrl encoding:NSUTF8StringEncoding error:&error];
    NSString* encodedPoints = [apiResponse stringByMatching:@"points:\\\"([^\\\"]*)\\\"" capture:1L];

    return [self decodePolyLine:[encodedPoints mutableCopy]];
}

Следующий код - настоящее волшебство (декодер для ответа, который мы получили от API). Я не изменил бы этот код, если бы я не знал, что я делаю:)

- (NSMutableArray *)decodePolyLine:(NSMutableString *)encodedString
{
    [encodedString replaceOccurrencesOfString:@"\\\\" withString:@"\\"
                                  options:NSLiteralSearch
                                    range:NSMakeRange(0, [encodedString length])];
    NSInteger len = [encodedString length];
    NSInteger index = 0;
    NSMutableArray *array = [[NSMutableArray alloc] init];
    NSInteger lat=0;
    NSInteger lng=0;
    while (index < len) {
        NSInteger b;
        NSInteger shift = 0;
        NSInteger result = 0;
        do {
            b = [encodedString characterAtIndex:index++] - 63;
            result |= (b & 0x1f) << shift;
            shift += 5;
        } while (b >= 0x20);
        NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
        lat += dlat;
        shift = 0;
        result = 0;
        do {
            b = [encodedString characterAtIndex:index++] - 63;
            result |= (b & 0x1f) << shift;
            shift += 5;
       } while (b >= 0x20);
        NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
        lng += dlng;
        NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
        NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
        printf("\n[%f,", [latitude doubleValue]);
        printf("%f]", [longitude doubleValue]);
        CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
        [array addObject:loc];
    }
    return array;
}

Эта функция нарисует маршрут и добавит наложение.

- (void)drawRoute
{
    int numPoints = [arrRoutePoints count];
    if (numPoints > 1)
    {
        CLLocationCoordinate2D* coords = malloc(numPoints * sizeof(CLLocationCoordinate2D));
        for (int i = 0; i < numPoints; i++)
        {
            CLLocation* current = [arrRoutePoints objectAtIndex:i];
            coords[i] = current.coordinate;
        }

        self.objPolyline = [MKPolyline polylineWithCoordinates:coords count:numPoints];
        free(coords);

        [objMapView addOverlay:objPolyline];
        [objMapView setNeedsDisplay];
    }
}

Следующий код выровняет карту по центру.

- (void)centerMap
{
    MKCoordinateRegion region;

    CLLocationDegrees maxLat = -90;
    CLLocationDegrees maxLon = -180;
    CLLocationDegrees minLat = 90;
    CLLocationDegrees minLon = 180;

    for(int idx = 0; idx < arrRoutePoints.count; idx++)
    {
        CLLocation* currentLocation = [arrRoutePoints objectAtIndex:idx];

        if(currentLocation.coordinate.latitude > maxLat)
            maxLat = currentLocation.coordinate.latitude;
        if(currentLocation.coordinate.latitude < minLat)
            minLat = currentLocation.coordinate.latitude;
        if(currentLocation.coordinate.longitude > maxLon)
            maxLon = currentLocation.coordinate.longitude;
        if(currentLocation.coordinate.longitude < minLon)
            minLon = currentLocation.coordinate.longitude;
    }

    region.center.latitude     = (maxLat + minLat) / 2;
    region.center.longitude    = (maxLon + minLon) / 2;
    region.span.latitudeDelta  = maxLat - minLat;
    region.span.longitudeDelta = maxLon - minLon;

    [objMapView setRegion:region animated:YES];
}

Надеюсь, это кому-нибудь поможет.

24 голосов
/ 14 мая 2010

Это сложный вопрос.Это невозможно сделать с помощью MapKit: достаточно просто нарисовать линии, когда вы знаете координаты, но MapKit не предоставит вам доступ к дорогам или другой информации о маршруте.Я бы сказал, что вам нужно вызвать внешний API для получения ваших данных.

Я играл с API cloudmade.com.Сервер векторного потока должен вернуть то, что вам нужно, а затем вы можете нарисовать это на своей карте.Однако из-за расхождений между картами Google и картами OSM , используемыми в облачной среде, может возникнуть необходимость в использовании карт, созданных в облачной среде, полностью: у них есть эквивалент MapKit.

PS: другие поставщики карт- Google, Bing и т. Д. Также могут предоставлять эквивалентные каналы данных.Я только недавно смотрел на OSM / Cloudmade.

PPS: Ничто из этого не является тривиальным новичком!Желаем удачи!

12 голосов
/ 14 мая 2010

Andiih понял это правильно. MapKit не позволит вам сделать это. К сожалению, Google не позволит вам делать то, что вы хотите.

Когда Apple анонсировала MapKit и все, они также прямо заявили, что любые навигационные приложения будут BYOM: принесите свои собственные карты, поэтому любое навигационное приложение использует собственный набор картографических инструментов.

Условия использования Google запрещают вам даже показывать маршруты поверх их карт:

http://code.google.com/intl/de/apis/maps/iphone/terms.html

Ограничения лицензии:

10,9 использовать Сервис или Контент с любыми продуктами, системами или приложениями для или в связи с:

(а) навигация в реальном времени или маршрут руководство, включая, но не ограничиваясь пошаговое руководство по маршруту, которое синхронизированы с положением пользовательское сенсорное устройство;

(б) любые системы или функции для автоматическое или автономное управление поведение автомобиля; или

(c) диспетчеризация, управление автопарком, отслеживание активов предприятия или подобное корпоративные приложения (Google API Карт можно использовать для отслеживания активов (например, автомобили, автобусы или другие транспортные средства), пока отслеживание приложение доступно для общественность бесплатно. Например, Вы можете предложить бесплатный общедоступный API Карт Реализация, которая отображает в режиме реального времени общественный транспорт или другой транспорт информация о состоянии.

К сожалению, это включает в себя то, что вы хотели бы сделать. Надеюсь, однажды MapKit будет расширен, чтобы позволить такие функции ... хотя вряд ли.

Удачи.

5 голосов
/ 01 июля 2010

Возможно, вы захотите взглянуть на https://github.com/leviathan/nvpolyline Это решение особенно предназначено для версий iPhone OS до v.4.0

Хотя его также можно использовать в v.4.0. Надеюсь, это поможет.

4 голосов
/ 14 февраля 2015

Получить и нарисовать маршрут на карте очень просто с iOS 7 API:

MKDirectionsRequest *directionsRequest = [[MKDirectionsRequest alloc] init];

// Set the origin of the route to be current user location
[directionsRequest setSource:[MKMapItem mapItemForCurrentLocation]];

// Set the destination point of the route
CLLocationCoordinate2D destinationCoordinate = CLLocationCoordinate2DMake(34.0872, 76.235);
MKPlacemark *destinationPlacemark = [[MKPlacemark alloc] initWithCoordinate:destinationCoordinate addressDictionary:nil];
[directionsRequest setDestination:[[MKMapItem alloc] initWithPlacemark:destinationPlacemark]];

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

// Requesting route information from Apple Map services
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
    if (error) {
        NSLog(@"Cannot calculate directions: %@",[error localizedDescription]);
    } else {
        // Displaying the route on the map
        MKRoute *route = [response.routes firstObject];
        [mapView addOverlay:route.polyline];
    }
}];
4 голосов
/ 05 января 2011

Попробуйте MapKit-Route-Directions ( GitHub ).

3 голосов
/ 12 марта 2012

Просто, чтобы уточнить, похоже, что обсуждается пара вещей. Один из них - это способ получить вершины маршрута, а другой - нарисовать наложение на карте, используя эти вершины. Я знаю API MapQuest, поэтому у меня есть несколько ссылок на них ниже - у Google и Bing есть эквиваленты, я думаю.

1) Получение вершин маршрута
Если вы ищете новые координаты маршрута для рисования наложения маршрута, вы можете использовать вызов веб-службы для веб-службы маршрутизации - я предполагаю, что вы используете здесь JavaScript для отображения карты. Если вы используете собственный код, вы все равно можете подключиться к веб-службе или использовать собственный вызов (т. Е. В MapQuest iPhone SDK есть собственный маршрутный вызов).

Большинство служб маршрутов должны возвращать «точки формы» маршрута, чтобы вы могли рисовать.

Вот несколько примеров использования MapQuest- Web-сервис Directions для получения точек формы (см. Возвращаемый объект Shape) - http://www.mapquestapi.com/directions/

2) Нанесение оверлея
Когда у вас есть вершины, вам нужно их нарисовать. Я думаю, что большинство API JavaScript-карт будут иметь некоторый класс оверлеев. Вот MapQuest один: http://developer.mapquest.com/web/documentation/sdk/javascript/v7.0/overlays#line

3) Выполнение одним звонком
В MapQuest также есть несколько удобных функций для вызова маршрута и рисования линии - я не могу опубликовать более двух ссылок! Поэтому перейдите по ссылке выше и найдите «роутинг» в навигационной панели слева.

3 голосов
/ 05 марта 2012

MapQuest имеет SDK, который заменяет MapKit. В настоящее время он находится в бета-версии, но находится в стадии активной разработки.

Позволяет наложения, маршрутизации и геокодирования.

API Карт MapQuest для iOS

1 голос
/ 25 февраля 2015

Для обновления этого вопроса не требуется внешний apk, начиная с iOS7.

Здесь очень простое и эффективное решение:

http://technet.weblineindia.com/mobile/draw-route-between-2-points-on-map-with-ios7-mapkit-api/2/

Я знаю, что вопрос касался iOS 6, но я верю, что это решение будет полезным для многих людей.

Единственное, чего не хватает в этом решении, это реализовать следующий метод делегата для отображения начального и конечного выводов

-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...