Подтвердить что ты не робот

Рисование маршрута в MapKit в iOS

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

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

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

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

Предоставляет ли iOS 6 прямой путь для этой проблемы?

4b9b3361

Ответ 1

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

Я играл с API cloudmade.com. Сервер векторного потока должен возвращать то, что вам нужно, и затем вы можете нарисовать его по карте. Однако расхождения между картами Google и картами

Ответ 2

Следующий 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];
}

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

Ответ 3

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

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

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

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

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

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

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

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

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

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

Удачи.

Ответ 4

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

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

Ответ 6

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

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

API карт MapQuest для iOS

Ответ 7

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

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

Большинство сервисов направлений должны возвращать "shapepoints" маршрута, чтобы вы могли рисовать.

Вот несколько примеров использования MapQuest- Направления веб-службы, чтобы получить shapepoints (см. Объект возврата формы) - http://www.mapquestapi.com/directions/

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

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

Ответ 8

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

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];
    }
}];

Ответ 9

Чтобы обновить этот вопрос, нет необходимости в внешнем 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