2010-05-14 16 views
53

Desidero disegnare un percorso tra due posizioni sulla mappa. Qualcosa come una guida turistica. Quando il turista fa clic su un'altra posizione, desidero essere in grado di tracciare un percorso; e informa sulla distanza dalla posizione corrente.Disegno di un percorso in MapKit in iPhone SDK

Sono a conoscenza di siti su Internet che indicano come disegnare polilinee sulla mappa. Ma la maggior parte degli esempi aveva un file .csv precaricato con varie coordinate.

Esiste un modo alternativo per ottenere le coordinate da Google o da qualsiasi altro fornitore, in quanto la posizione viene selezionata dinamicamente.

Se NO, come ottengo le informazioni per le coordinate intermedie?

iOS 6 fornisce un modo diretto per questo problema?

+0

Prova questo, spero che vi aiuterà u https://github.com/Surya121/SBMapWithRoute – iCoder4777

+0

http: //iphonegeeksworld.wordpress.com/2010/09/08/salotti percorsi-onto-mkmapview-con-ufficiali-google-maps-directions-API/ – viral

+0

Se si utilizza il codice di questo aggiornamento è neccessary http: // StackOverflow .com/questions/8166179/regex-and-ios5-stringbymatching-nsregularexpression –

risposta

24

Questo è un problema. Non c'è modo di farlo con MapKit: è abbastanza facile tracciare linee quando si conoscono le coordinate, ma MapKit non ti darà accesso alle strade o ad altre informazioni di routing. Direi che devi chiamare un'API esterna per ottenere i tuoi dati.

Ho giocato con le API di cloudmade.com. Il server del flusso vettoriale dovrebbe restituire quello che ti serve, e quindi puoi disegnarlo sulla tua mappa. Tuttavia, le discrepanze tra le mappe di Google e le mappe OSM utilizzate da cloudmade potrebbero farti desiderare di utilizzare le mappe cloud create completamente: hanno un equivalente a MapKit.

P.S .: Altri fornitori di mappe - Google, Bing, ecc. Possono anche fornire feed di dati equivalenti. Ho appena visto OSM/Cloudmade di recente.

P.P.S .: Niente di tutto questo è roba da principianti banale! Buona fortuna!

12

E ha ragione. MapKit non ti permetterà di farlo. Purtroppo, Google non ti consente di fare ciò che vuoi fare.

Quando Apple ha annunciato MapKit e tutti, hanno anche dichiarato esplicitamente che qualsiasi applicazione di navigazione sarebbe BYOM: Porta le tue mappe, quindi qualsiasi applicazione di navigazione utilizza il proprio set di strumenti di mappatura.

di Google Termini di servizio si limitano da anche la visualizzazione di percorsi in cima alla loro mappe:

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

Restrizioni della licenza:

10.9 utilizzare il Servizio o contenuti con eventuali prodotti, sistemi o applicazioni per o in connessione con:

(a) di navigazione in tempo reale o percorso guida, compreso ma non limitato a turn-by-turn guida percorso ovvero sincronizzato con la posizione di un dispositivo abilitato al sensore dell'utente ;

(b) qualsiasi sistema o funzione per il controllo automatico o autonomo del comportamento del veicolo ; o

(c) la spedizione, la gestione della flotta, affari asset tracking, o simili applicazioni aziendali (i Google Maps API può essere utilizzato per tenere traccia delle risorse (come le automobili, autobus o altri veicoli) il più a lungo il monitoraggio applicazione viene messa a disposizione del pubblico senza spese. per esempio, si possono offrire un libero, mappe pubbliche API implementazione che consente di visualizzare in tempo reale mezzi pubblici o altri mezzi di trasporto informazioni di stato.

Purtroppo, questo include ciò che vorresti fare. Speriamo che un giorno MapKit verrà ampliato per consentire tali funzionalità ... anche se improbabile.

Buona fortuna.

+1

PRN non dice che sta provando a fare qualsiasi impresa o turn-by-turn: solo che vuole sovrapporre le direzioni. Questo è qualcosa che puoi fare con l'API JavaScript di Google Maps (credo), ma non con MapKit. Ovviamente hai più familiarità con l'API di Google di me - se non è il turno dopo giro c'è un modo per ottenere i vettori stradali? [guarda questa domanda mi ha interessato ora!] – Andiih

+1

non è una svolta a turno, ma è la guida di percorso, non è vero? – Daniel

5

Si potrebbe desiderare di avere uno sguardo a https://github.com/leviathan/nvpolyline Questa soluzione è particolarmente rivolto a versioni iPhone OS precedenti a v.4.0

Anche se può essere utilizzato anche a Hope v.4.0 questo aiuta.

+0

Hi Colins, Prima di tutto ci scusiamo per la risposta ritardata ... ma con l'esempio sopra menzionato, le coordinate sono hardcoded all'interno dell'applicazione, quello che voglio è ottenere le coordinate come e quando la posizione è selezionata ... non qualcosa in cui le coordinate sono precaricate. Ad esempio, un turista potrebbe scegliere qualsiasi posizione casuale in una città e dovrebbe essere fornito il percorso in base alle sue coordinate correnti. La coordinata della località selezionata potrebbe non essere precaricata. – PRN

+0

PRN si prega di andare al progetto GitHub della polilinea e aprire un rapporto sul problema (http://github.com/mobilemelting/nvpolyline/issues). Cercherò di incorporare una soluzione per il tuo problema nel progetto. – leviathan

+0

L'URL corretto è https://github.com/leviathan/nvpolyline – leviathan

3

MapQuest ha un SDK che sostituisce MapKit. È attualmente in beta, ma in fase di sviluppo attivo.

Consente sovrapposizioni, routing e geocodifica.

MapQuest iOS Maps API

3

Giusto per chiarire, sembra che ci sono un paio di cose in discussione. Uno è un modo per ottenere i vertici di una rotta e l'altro è disegnare una sovrapposizione sulla mappa usando quei vertici. Conosco le API di MapQuest, quindi ho alcuni link per quelli di seguito: Google e lo standard Bing hanno equivalenti.

1) Ottenere i vertici di un percorso
Se stai cercando le nuove coordinate di un percorso per tracciare un percorso di sovrapposizione, puoi utilizzare una chiamata di servizio Web a un servizio di routing Web - Sto assumendo te stai usando JavaScript qui per visualizzare la mappa. Se si utilizza il codice nativo, è comunque possibile accedere a un servizio Web o utilizzare una chiamata nativa (ovvero, l'IPK di iPhone di MapQuest ha una chiamata alla route nativa).

La maggior parte dei servizi di indicazioni stradali deve restituire i "punti di forza" del percorso in modo da poter disegnare.

Ecco alcuni esempi che utilizzano MapQuest- Indicazioni Web Service per ottenere shapepoints (vedere l'oggetto di ritorno Forma) - http://www.mapquestapi.com/directions/

2) Disegno di una sovrapposizione
Una volta che avete i vostri vertici, è necessario disegnare loro. Penso che la maggior parte delle API di mappe JavaScript avrà una classe di overlay di qualche tipo. Ecco il MapQuest uno: http://developer.mapquest.com/web/documentation/sdk/javascript/v7.0/overlays#line

3) Farlo con una sola chiamata
MapQuest hanno anche alcune funzioni di convenienza per effettuare la chiamata percorso e tracciare la linea per voi - non posso postare più di due link! Quindi vai al link sopra e cerca "routing" nella barra di navigazione a sinistra.

61

Il seguente viewDidLoad (1) imposta due posizioni, (2) rimuove tutte le annotazioni precedenti e (3) chiama le funzioni di aiuto definite dall'utente (per ottenere punti di percorso e tracciare il percorso).

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

Quello che segue è il metodo MKMapViewDelegate, che attira overlay (iOS 4.0 e versioni successive).

/* 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; 
} 

La seguente funzione otterrà entrambe le posizioni e preparerà l'URL per ottenere tutti i punti del percorso. E, naturalmente, chiamerà 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]]; 
} 

Il codice seguente è la vera magia (decodificatore per la risposta ricevuta dall'API). Non vorrei modificare il codice se non so quello che sto facendo :)

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

Questa funzione disegnerà un percorso e aggiungerò una sovrapposizione.

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

Il seguente codice centrerà l'allineamento della mappa.

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

Spero che questo possa aiutare qualcuno.

+0

Spero che il tuo metodo di tracciamento funzioni correttamente. Ho usato quasi la stessa funzione di quella denominata decodePolyLine nella tua. Ho ottenuto l'array di CLLocations ma sono rimasto bloccato dopo che il metodo "polylineWithCordinates" ha ottenuto un arrray di CLLocationCordinate2D e non sapevo come convertire il mio array in array CLLocationCordinate2D. Proverò il tuo metodo di tracciamento domani nel mio posto di lavoro. A proposito, potresti spiegare questa riga "CLLocationCoordinate2D * coords = malloc (numPoints * sizeof (CLLocationCoordinate2D));" – Nil

+1

@ rd4code 'CLLocationCoordinate2D * coords = malloc (numPoints * sizeof (CLLocationCoordinate2D));' - Assegna un chunk in memoria uguale alla dimensione dei nostri 'arrRoutePoints', con ciascuno degli oggetti indice come' CLLocationCoordinate2D'. Spero sia chiaro per te. – viral

+0

il tuo metodo ha funzionato oggi :). grazie e grazie per la spiegazione. . Inoltre voglio chiedere se c'è un altro modo per creare l'array CLLocationCoordinate2D? Voglio dire se il malloc è necessario? – Nil

3

Ottenere e disegnando un percorso sulla mappa è super facile con 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]; 
    } 
}]; 
+1

Come hai intenzione di fare lo stesso per i paesi senza supporto di direzione in MapKit? – madLokesh

2

Per aggiornare a questa domanda, non v'è alcuna necessità di apk esterni dal iOS7.

Ecco una soluzione molto semplice ed efficace:

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

So che la domanda riguardava iOS 6 ma credo che questa soluzione sarà utile per molte persone.

L'unica cosa che manca in questa soluzione sta attuando il seguente metodo delegato per visualizzare l'inizio e la fine del perno

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