Disegnare un percorso in MapKit in iPhone SDK

Voglio 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.

Sono a conoscenza di siti su Internet che raccontano 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 dynamicmente.

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

IOS 6 fornisce un modo diretto per questo problema?

Questo è difficile. 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 stream 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 possono farti desiderare di usare le mappe cloudmade fino a quando hanno un equivalente a MapKit.

PS: altri fornitori di mappe – Google, Bing, ecc. Possono anche fornire feed di dati equivalenti. Ho appena visto OSM / Cloudmade di recente.

PPS: Niente di tutto questo è roba da principianti banali! Buona fortuna!

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 disegna la sovrapposizione (iOS 4.0 e successive).

 /* MKMapViewDelegate Meth0d -- for viewForOverlay*/ - (MKOverlayView*)mapView:(MKMapView*)theMapView viewForOverlay:(id )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 che abbiamo ricevuto dall’API). Non modificherei quel codice a meno che non sappia cosa 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.

Andiih 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 mapping.

I Termini di servizio di Google ti impediscono persino di visualizzare percorsi sopra le loro mappe:

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

Restrizioni di licenza:

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

(a) navigazione in tempo reale o guida a destinazione, incluso, a titolo esemplificativo ma non esaustivo, il percorso guidato per svolta che è sincronizzato con la posizione del dispositivo abilitato al sensore di un utente;

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

(c) spedizione, gestione della flotta, tracciamento delle attività aziendali o applicazioni aziendali simili (l’API di Google Maps può essere utilizzata per tenere traccia delle risorse (come automobili, autobus o altri veicoli) a condizione che l’applicazione di tracciamento sia resa disponibile al pubblico senza Ad esempio, puoi offrire un’implementazione pubblica gratuita di Maps Maps che visualizza in tempo reale il trasporto pubblico o altre informazioni sullo stato del trasporto.

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

In bocca al lupo.

Si consiglia di dare un’occhiata a https://github.com/leviathan/nvpolyline Questa soluzione è particolarmente mirata alle versioni del sistema operativo iPhone precedenti alla v.4.0

Anche se può essere utilizzato anche in v.4.0 Spero che questo aiuti.

Prova MapKit-Route-Directions ( GitHub ).

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

Permette sovrapposizioni, routing e geocodifica.

API MapQuest iOS Maps

Giusto per chiarire, sembra che ci siano 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 collegamenti per i seguenti: Google e Bing hanno equivalenti, penso.

1) Ottenere i vertici di un percorso
Se stai cercando le nuove coordinate di un percorso per disegnare una sovrapposizione di percorsi, puoi utilizzare una chiamata di servizio Web a un servizio di routing Web. Suppongo che tu stia utilizzando JavaScript qui per visualizzare la mappa. Se si utilizza il codice nativo, è comunque ansible 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 dovrebbe restituire i “punti di forza” del percorso in modo da poter disegnare.

Ecco alcuni esempi che utilizzano MapQuest- Directions Web Service per ottenere punti di pace (vedere l’object Shape return) – http://www.mapquestapi.com/directions/

2) Disegnare una sovrapposizione
Una volta che hai i tuoi vertici, devi disegnarli. Penso che la maggior parte delle API di mappe JavaScript avrà una class di overlay di qualche tipo. Ecco quello di MapQuest: http://developer.mapquest.com/web/documentation/sdk/javascript/v7.0/overlays#line

3) Farlo con una chiamata
MapQuest ha anche alcune funzioni utili per fare in modo che il percorso chiami e traccia la linea per te: non posso pubblicare più di due link! Quindi vai al link sopra e cerca “routing” nella barra di navigazione a sinistra.

Ottenere e disegnare un percorso sulla mappa è semplicissimo con l’API di 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]; } }]; 

Per aggiornare questa domanda, non è necessario un apk esterno da 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 è l’implementazione del seguente metodo delegato per visualizzare il pin iniziale e finale

 -(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation