web-dev-qa-db-ja.com

iOSのMapKitでルートを描画する

地図上の2つの場所の間にルートを描きたい。ツアーガイドのようなもの。観光客が別の場所をクリックすると、ルートを描画できるようになります。同様に、現在の場所からの距離についても通知します。

地図上にポリラインを描画する方法を伝えるインターネット上のサイトを知っています。ただし、ほとんどの例には、さまざまな座標のプリロードされた.csvファイルがありました。

場所が動的に選択されるため、Googleまたは他のプロバイダーから座標を取得する代替方法はありますか。

いいえの場合、中間座標の情報を取得するにはどうすればよいですか?

IOS 6はこの問題に直接的な方法を提供しますか?

54
PRN

これはトリッキーなものです。 MapKitでそれを行う方法はありません。座標がわかっているときに線を引くのは簡単ですが、MapKitでは道路やその他のルーティング情報にアクセスできません。データを取得するには、外部APIを呼び出す必要があると思います。

私はcloudmade.com APIで遊んでいます。ベクターストリームサーバーは必要なものを返す必要があり、それをマップ上に描画できます。ただし、Googleマップと [〜#〜] osm [〜#〜] cloudmadeで使用されるマップとの不一致により、cloudmadeマップをずっと使用したくなる場合があります。MapKitと同等です。

追伸:他のマッピングプロバイダー-Google、Bingなども同等のデータフィードを提供する場合があります。私は最近OSM/Cloudmadeを見てきました。

P.P.S .:これはどれも些細な初心者のものではありません!幸運を祈ります!

24
Andiih

次のviewDidLoadは、(1)2つの場所を設定し、(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];
}

これが誰かの助けになることを願っています。

61
viral

Andiihはそれを正しく理解しています。 MapKitではそれができません。残念ながら、Googleもあなたがやりたいことをすることはできません。

Apple MapKitとそのすべてを発表したとき、ナビゲーションアプリケーションはBYOM:Bring Your Own Mapsであるため、ナビゲーションアプリケーションは独自のマッピングツールのセットを使用することを明示的に述べました。

Googleの利用規約では、地図の上にルートを表示することさえ制限されています。

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

ライセンスの制限:

10.9サービスまたはコンテンツを製品、システム、またはアプリケーションで使用するか、以下に関連して:

(a)リアルタイムナビゲーションまたはルートガイダンス。これには、ユーザーのセンサー対応デバイスの位置に同期するターンバイターンのルートガイダンスが含まれますが、これらに限定されません。

(b)車両挙動の自動または自律制御のためのシステムまたは機能。または

(c)追跡アプリケーションが一般に公開されている限り、発送、車両管理、ビジネス資産追跡、または類似のエンタープライズアプリケーション(Google Maps APIを使用して資産(自動車、バス、その他の車両など)を追跡できます)たとえば、無料の公共Maps API実装を提供して、リアルタイムの公共交通機関やその他の交通状況情報を表示できます。

悲しいことに、これにはあなたがやりたいことが含まれています。できれば、いつかMapKitを拡張してそのような機能を使用できるようにすることをお勧めします。

がんばろう。

12
Daniel Amitay

https://github.com/leviathan/nvpolyline このソリューションは、v.4.0より前のiPhone OSバージョンを特に対象としています。

V.4.0でも使用できますが、これが役立つことを願っています。

5
leviathan

試してみてくださいMapKit-Route-DirectionsGitHub ).

4
iOS_User

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
NAlexN

MapQuestには、MapKitのドロップイン代替品であるSDKがあります。現在ベータ版ですが、活発に開発中です。

オーバーレイ、ルーティング、およびジオコーディングが可能です。

MapQuest iOS Maps API

3
Fabian

明確にするために、議論されていることがいくつかあるようです。 1つはルートの頂点を取得する方法であり、もう1つはそれらの頂点を使用してマップ上にオーバーレイを描画する方法です。私はMapQuest APIを知っているので、以下のリンクがいくつかあります。Googleと Bing は同等のものを持っていると思います。

1)ルートの頂点を取得する
ルートオーバーレイを描画するためにルートの新しい座標を探している場合は、ルーティングWebサービスへのWebサービス呼び出しを使用できます。ここでJavaScriptを使用して表示することを想定しています地図。ネイティブコードを使用している場合でも、Webサービスにアクセスするか、ネイティブ呼び出しを使用できます(つまり、MapQuest iPhone SDKにはネイティブルート呼び出しが含まれています)。

ルートサービスのほとんどは、描画できるようにルートの「シェイプポイント」を返す必要があります。

MapQuest- Directions Webサービスを使用してシェイプポイントを取得する例を次に示します(シェイプリターンオブジェクトを参照)- http://www.mapquestapi.com/directions/

2)オーバーレイの描画
頂点を作成したら、それらを描画する必要があります。ほとんどのJavaScriptマップAPIには、ある種のオーバーレイクラスがあると思います。 MapQuestのものは次のとおりです。 http://developer.mapquest.com/web/documentation/sdk/javascript/v7.0/overlays#line

3)1回の呼び出しでそれを行う
MapQuestには、ルート呼び出しを行って線を引く便利な機能もあります。2つ以上のリンクを投稿することはできません。そのため、上のリンクに移動して、左側のナビゲーションバーで「ルーティング」を探します。

3
Roman

この質問を更新するには、iOS7以降、外部apkは必要ありません。

ここに非常にシンプルで効果的なソリューション:

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
1
Omaty