Programing

iOS의 MapKit에서 경로 그리기

즐거운 cyworld 2021. 1. 11. 07:31
반응형

iOS의 MapKit에서 경로 그리기


지도에서 두 위치 사이에 경로를 그리고 싶습니다. 여행 가이드와 같은 것. 관광객이 다른 위치를 클릭하면 경로를 그릴 수 있기를 원합니다. 뿐만 아니라 현재 위치로부터의 거리에 대해서도 알려줍니다.

지도에 폴리 라인을 그리는 방법을 알려주는 인터넷 사이트를 알고 있습니다. 그러나 대부분의 예제에는 다양한 좌표가있는 미리로드 된 .csv 파일이 있습니다.

위치가 동적으로 선택되므로 Google 또는 다른 공급자로부터 좌표를 가져 오는 다른 방법이 있습니까?

아니오 인 경우 중간 좌표에 대한 정보를 어떻게 얻습니까?

iOS 6이이 문제에 대한 직접적인 방법을 제공합니까?


이것은 까다로운 것입니다. MapKit으로는 그렇게 할 수있는 방법이 없습니다. 좌표를 알면 선을 그리는 것은 쉽지만 MapKit은 도로 나 기타 경로 정보에 대한 액세스를 제공하지 않습니다. 데이터를 얻으려면 외부 API를 호출해야한다고 말하고 싶습니다.

나는 cloudmade.com API를 가지고 놀았습니다. 벡터 스트림 서버는 필요한 것을 반환 한 다음지도 위에 그릴 수 있습니다. 그러나 Google지도와 cloudmade에서 사용 하는 OSM 지도 사이의 불일치 로 인해 Cloudmade지도를 계속 사용하고 싶을 수 있습니다. MapKit에 해당합니다.

추신 : 다른 매핑 제공 업체-Google, Bing 등도 동등한 데이터 피드를 제공 할 수 있습니다. 최근에 OSM / Cloudmade를 살펴 보았습니다.

PPS :이 중 어느 것도 사소한 초보자 물건이 아닙니다! 행운을 빕니다!


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

나는 이것이 누군가를 도울 수 있기를 바랍니다.


Andiih가 옳았습니다. MapKit은 그렇게 할 수 없습니다. 안타깝게도 Google은 사용자가 원하는 작업을 수행하도록 허용하지 않습니다.

When Apple announced MapKit and all, they also explicitly stated that any navigational applications would be BYOM: Bring Your Own Maps, so any navigation application uses their own set of mapping tools.

Google's Terms of Service restrict you from even displaying routes on top of their maps:

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

License Restrictions:

10.9 use the Service or Content with any products, systems, or applications for or in connection with:

(a) real time navigation or route guidance, including but not limited to turn-by-turn route guidance that is synchronized to the position of a user's sensor-enabled device;

(b) any systems or functions for automatic or autonomous control of vehicle behavior; or

(c) dispatch, fleet management, business asset tracking, or similar enterprise applications (the Google Maps API can be used to track assets (such as cars, buses or other vehicles) as long as the tracking application is made available to the public without charge. For example, you may offer a free, public Maps API Implementation that displays real-time public transit or other transportation status information.

Sadly, this includes what you would like to do. Hopefully one day MapKit will be expanded to allow such features... although unlikely.

Good luck.


You might want to have a look at https://github.com/leviathan/nvpolyline This solution is especially targeted at iPhone OS versions prior to v.4.0

Although it can also be used in v.4.0 Hope this helps.


Try MapKit-Route-Directions (GitHub).


Obtaining and drawing a route on the map is super easy with 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];
    }
}];

MapQuest has an SDK that's a drop-in replacement for MapKit. It's currently in beta, but under active development.

It allows overlays, routing, and geocoding.

MapQuest iOS Maps API


Just to clarify, it looks like there are a couple of things being discussed. One is a way to get the vertices of a route and the other is to draw an overlay on the map using those vertices. I know the MapQuest APIs, so I have some links for those below - Google and Bing have equivalents I think.

1) Getting vertices of a route
If you're looking for the new coordinates of a route to draw a route overlay, you can either use a web service call to a routing web service - I'm assuming you're using JavaScript here to display the map. If you're using native code, you can still hit a web service or you can use a native call (that is, the MapQuest iPhone SDK has a native route call in it).

Most of the directions services should return the "shapepoints" of the route so that you can draw.

Here are some examples using MapQuest- Directions Web Service to get shapepoints (see the Shape return object) - http://www.mapquestapi.com/directions/

2) Drawing an overlay
Once you have your vertices, you need to draw them. I think most JavaScript map APIs will have an overlay class of some sort. Here's the MapQuest one: http://developer.mapquest.com/web/documentation/sdk/javascript/v7.0/overlays#line

3) Doing it with one call
MapQuest also have some convenience functions to make the route call and draw the line for you - I can't post more than two links! So go to the link above and look for "routing" in the navigation bar on the left.


To update this question, there is no need to external apk since iOS7.

Here a very simple and effective solution :

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

I know the question was about iOS 6 but I believe that this solution will be useful for many people.

The only thing missing in this solution is implementing the following delegate method to display the beginning and ending pin

-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation

ReferenceURL : https://stackoverflow.com/questions/2834523/drawing-a-route-in-mapkit-in-ios

반응형