2013-04-10 10 views
20

Sto disegnando un percorso tra due punti in una mappa. Ricevo i punti in questo modo:Polilinea di decodifica con la nuova API di Google Maps

StringBuilder urlString = new StringBuilder(); 
    urlString.append("http://maps.googleapis.com/maps/api/directions/json"); 
    urlString.append("?origin=");// from 
    urlString.append(Double.toString(src.latitude)); 
    urlString.append(","); 
    urlString.append(Double.toString(src.longitude)); 
    urlString.append("&destination=");// to 
    urlString.append(Double.toString(dest.latitude)); 
    urlString.append(","); 
    urlString.append(Double.toString(dest.longitude)); 
    urlString.append("&sensor=false&mode="); 
    if (tipo != null) { 
     urlString.append(tipo); 
    } 
return urlString.toString; 

ricevo la risposta da Google, e ottengo il JSON:

resp = new JSONObject(builder.toString()); 
       Log.i("Location", "Contenido del kml: "+resp); 
       JSONArray routeObject = resp.getJSONArray("routes"); 
       JSONObject routes = routeObject.getJSONObject(0); 
       JSONObject overviewPolylines = routes 
         .getJSONObject("overview_polyline"); 
       String encodedString = overviewPolylines.getString("points"); 
       ArrayList<LatLng> puntos=decodePoly(encodedString); 

La risposta che ricevo da Google: (in formato JSON):

Response: {"status":"OK","routes":[{"waypoint_order":[],"summary":"R-3 and A-3","bounds":{"southwest":{"lng":-3.676540000000001,"lat":40.00040000000001},"northeast":{"lng":-2.99933,"lat":40.43357}},"legs":[{"duration":{"value":3267,"text":"54 mins"},"distance":{"value":85039,"text":"85.0 km"},"end_location":{"lng":-2.99933,"lat":40.00040000000001},"start_address":"Calle del General Díaz Porlier, 91, 28006 Madrid, Spain","end_address":"Camino Veinticuatro, 2, 16400 Tarancón, Cuenca, Spain","start_location":{"lng":-3.676540000000001,"lat":40.43331000000001},"via_waypoint":[],"steps":[{"html_instructions":"Head <b>north<\/b> on <b>Calle del Gral Díaz Porlier<\/b> toward <b>Calle de Maldonado<\/b>","duration":{"value":6,"text":"1 min"},"distance":{"value":29,"text":"29 m"},"end_location":{"lng":-3.676520000000001,"lat":40.43357},"polyline":{"points":"[email protected]"},"travel_mode":"DRIVING","start_location":{"lng":-3.676540000000001,"lat":40.43331000000001}},{"html_instructions":"Take the 1st <b>right<\/b> onto <b>Calle de Maldonado<\/b>","duration":{"value":62,"text":"1 min"},"distance":{"value":266,"text":"0.3 km"},"end_location":{"lng":-3.6734,"lat":40.43345},"polyline":{"points":"[email protected]@[email protected]"},"travel_mode":"DRIVING","start_location":{"lng":-3.676520000000001,"lat":40.43357}},{"html_instructions":"Take the 2nd <b>right<\/b> onto <b>Calle de Fco. Silvela<\/b>","duration":{"value":57,"text":"1 min"},"distance":{"value":245,"text":"0.2 km"},"end_location":{"lng":-3.671830000000001,"lat":40.4316},"polyline":{"points":"[email protected]@[email protected]]pBeBLK"},"travel_mode":"DRIVING","start_location":{"lng":-3.6734,"lat":40.43345}},{"html_instructions":"Slight <b>right<\/b> onto <b>Calle de Francisco Silvela<\/b>","duration":{"value":51,"text":"1 min"},"distance":{"value":437,"text":"0.4 km"},"end_location":{"lng":-3.66913,"lat":40.42827},"polyline":{"points":"oxwuF|clUJADAFCbBkAjAeA`BoA^[XUPMLMFEnAeALIdBuAZUPMXS"},"travel_mode":"DRIVING","start_location":{"lng":-3.671830000000001,"lat":40.4316}},{"html_instructions":"Turn <b>right<\/b> onto <b>Pl. de Manuel Becerra<\/b>","duration":{"value":32,"text":"1 min"},"distance":{"value":154,"text":"0.2 km"},"end_location":{"lng":-3.668380000000001,"lat":40.42827},"polyline":{"points":"ucwuF`[email protected][email protected]@@@@[email protected]@@[email protected]@[email protected]@[email protected]"},"travel_mode":"DRIVING","start_location":{"lng":-3.66913,"lat":40.42827}},{"html_instructions":"Turn <b>right<\/b> onto <b>Calle Alcala<\/b>","duration":{"value":61,"text":"1 min"},"distance":{"value":709,"text":"0.7 km"},"end_location":{"lng":-3.66107,"lat":40.43126000000001},"polyline":{"points":"[email protected]}[email protected]@[[email protected]@kB?KAQ]aAI[[email protected]@[email protected]"},"travel_mode":"DRIVING","start_location":{"lng":-3.668380000000001,"lat":40.42827}},{"html_instructions":"Turn <b>right<\/b> onto the ramp to <b>M-30\/A-3\/A-4<\/b>","duration":{"value":44,"text":"1 min"},"distance":{"value":453,"text":"0.5 km"},"end_location":{"lng":-3.660580000000001,"lat":40.42720000000001},"polyline":{"points":"kvwuFt`jU\\[email protected]?rCOvDY"},"travel_mode":"DRIVING","start_location":{"lng":-3.66107,"lat":40.43126000000001}},{"html_instructions":"Continue straight","duration":{"value":45,"text":"1 min"},"distance":{"value":1009,"text":"1.0 km"},"end_location":{"lng":-3.659120000000001,"lat":40.41822000000001},"polyline":{"points":"_}vuFr}[email protected]@[email protected]|[email protected]^[email protected]@[email protected]"},"travel_mode":"DRIVING","start_location":{"lng":-3.660580000000001,"lat":40.42720000000001}},{"html_instructions":"Take exit <b>7B<\/b> to merge onto <b>M-23<\/b> toward <b>Vicálvaro\/R-3\/Valencia<\/b>","duration":{"value":117,"text":"2 mins"},"distance":{"value":2552,"text":"2.6 km"},"end_location":{"lng":-3.63392,"lat":40.41499},"polyline":{"points":"{[email protected]^[email protected]@[email protected][email protected][email protected]@[email protected][email protected]@[email protected]@[email protected][email protected]{[email protected][@[email protected]@@G?A^{BjA}HF[[email protected]][email protected][email protected]@[email protected]@iGXmHDgFCgGG{DM 

Infine, decodifico la String ricevuta in questo modo, che ho trovato in molte risposte qui in Stackoverflow:

private ArrayList<LatLng> decodePoly(String encoded) { 

    Log.i("Location", "String received: "+encoded); 
    ArrayList<LatLng> poly = new ArrayList<LatLng>(); 
    int index = 0, len = encoded.length(); 
    int lat = 0, lng = 0; 

    while (index < len) { 
     int b, shift = 0, result = 0; 
     do { 
      b = encoded.charAt(index++) - 63; 
      result |= (b & 0x1f) << shift; 
      shift += 5; 
     } while (b >= 0x20); 
     int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); 
     lat += dlat; 

     shift = 0; 
     result = 0; 
     do { 
      b = encoded.charAt(index++) - 63; 
      result |= (b & 0x1f) << shift; 
      shift += 5; 
     } while (b >= 0x20); 
     int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); 
     lng += dlng; 

     LatLng p = new LatLng((int) (((double) lat /1E5)* 1E6), (int) (((double) lng/1E5 * 1E6))); 
     poly.add(p); 
    } 

    for(int i=0;i<poly.size();i++){ 
     Log.i("Location", "Point sent: Latitude: "+poly.get(i).latitude+" Longitude: "+poly.get(i).longitude); 
    } 
    return poly; 
} 

Questo è dove penso che l'errore è perché ho impostato un per vedere i punti che vengono decodificati, e la risposta è qualcosa di simile:

04-10 13:33:54.578: I/Location(25065): Point sent: Latitude: 90.0 Longitude: -110.0 
04-10 13:33:54.578: I/Location(25065): Point sent: Latitude: 90.0 Longitude: -120.0 
04-10 13:33:54.578: I/Location(25065): Point sent: Latitude: 90.0 Longitude: 100.0 
04-10 13:33:54.578: I/Location(25065): Point sent: Latitude: 90.0 Longitude: 120.0 
04-10 13:33:54.578: I/Location(25065): Point sent: Latitude: 90.0 Longitude: 40.0 

obviosly, questi punti sono male analizzato. Il risultato è, nessuna linea disegnata da nessuna parte.

La mia domanda è ... qualcuno sa come analizzare la risposta di Google e tradurla in oggetti LatLng (NON oggetti GeoPoints)?

Grazie!

EDIT:

Questa è la stringa che sta per essere decodificato:

04-10 13:50:51.608: I/Location(25065): String to decode: [email protected]}@[email protected]{[email protected]@[email protected]@[email protected]@[email protected]~ZwDtZuC`FKbCVjA`[email protected]@[email protected]][email protected]}DhC{PlBcM~GaY|DyS`BmPRy]yBu\UsNvAqObAuEnC}[email protected][}[email protected]}[email protected]`@~G}\|@aDdDoLn`@}[email protected]`JyV|[email protected]@{ZyBwVkBmOwB{^[email protected]@qYcCyS_DkPmAaK{@gRN{RbCkWrFgUbHmPxLsP|JwIpPwN|G}JfE}I|[email protected]]jCmXbHg\pIgSpGaLnN}P`JsHfVaNbQkHtZyIrOsCnTaCx\aA`[email protected]@nSRz]K`J{AxJiDfNkJjU{WbKkJpGeEpVkPpEiEzMcQjQw]nJyM~IoJ`IoKnH{NrOaWtIeJdNgNrLcPjKqOhIuI~MeJxKgErR{Cn]EjQkBjHqBfJeE|\yTlI_JvEqJxHsS|[email protected]~IeR|[email protected]@sNOoL_B}[email protected]]}N`CuO`D}GjHoHtFwC|[email protected]}BtHaF~D_FjLqSfGqE|[email protected]`BzNeAxQfAlJ{@jIwEjE}FvBuF|B{NtCsNrBgEdHiIdGuIxDoFpGkFhDaBrHyBbF[[email protected]{D|[email protected]@nE_F|Im`@tO_ZxCyEzJmKtHyElG_ClZeF|[email protected]|EuChGkHnK{[email protected][email protected]}[email protected]|BeGlEiYpD}[email protected]}[email protected]`ImMfMmXtFySpCkXRuN][email protected]}LxB{NvD{OjJaYbFsLnCcEtLoMfJyXzIiXbIiL~D_EzQcMjDeF|AcFhA_M`BkXpC_KjCsDnDeClQcHvEgElFqJfF_Jp\[email protected]]`WkWlVy`@nOcTz`@[email protected]_ZbNkQ~Tu^jJaUhCuIpHgUrPi\[email protected]@~McQh\e]vTaU~KcF~KoGhG{KzF{HzGmDbDwBfDiEzB}[email protected]@[email protected]@tDgC`ZeJnXkHrKmB~EeB~C{A`[email protected]@yEhDeOrCuQ|A}EvAwFdDgAfGSrHUJ\[email protected]@_A|[email protected]|C}[email protected]~Ds][email protected][email protected] 

Se con LatLng formiato si intende il modo in cui vengono creati gli oggetti LatLng, si può vedere nel metodo decodePoly. Questi oggetti LatLng vengono aggiunti agli oggetti PolylineOptions, e il presente aggiunti alla mappa, in questo modo:

PolylineOption ruta=new PolylineOptions(); 
for(int i=0;i<puntos.size();i++){ 
ruta.add(new LatLng(puntos.get(i).latitude, puntos.get(i).longitude));      
}//puntos is an array where the array returned by the decodePoly method are stored     
ruta.color(Color.RED).width(7);      
Polyline polygon=mapa.addPolyline(ruta); 
+0

Latta tu mostri qual è la tua risposta? e il tuo form di latlong? – GrIsHu

+0

Aggiungere una risposta di esempio. Molto probabilmente, è il formato 1E6 a causare il problema. –

+0

Ho provato a fare solo 'new LatLng (lat, lng)' nel metodo decodePoly, e nessun risultato. Inoltre, ho provato a rimuovere la parte 1E6 e nessun risultato ... – Fustigador

risposta

27

ho cambiato il decodePoly che stavo usando per questo che ho trovato dopo una lunga ricerca in Google, e ora il percorso è disegnato correttamente.

http://wptrafficanalyzer.in/blog/route-between-two-locations-with-waypoints-in-google-map-android-api-v2/

Modifica

LatLng p = new LatLng((int) (((double) lat /1E5)* 1E6), (int) (((double) lng/1E5 * 1E6))); 

per

LatLng p = new LatLng((((double) lat/1E5)),(((double) lng/1E5))); 

E ora funziona.

+0

Grazie mille :) – Nizam

+4

[android-maps-utils] (https://github.com/googlemaps/android-maps-utils) ha metodi di utilità per questo e molte altre cose utili che puoi fare su Google Maps – Zharf

+0

I Dovevo anche fare quel cambiamento che ha menzionato @Fustigador, ma non ho visto la sua nota su quel cambiamento fino a quando ho passato 20 minuti a capire da solo e poi scuotere la testa, una volta che mi rendo conto che ha già postato la correzione per questo. LOL Sono un manichino. – BigSauce

1

Ecco la funzione in Visual Basic, che utilizzo spesso.

Structure LatLng 
    Dim Lat As Decimal 
    Dim Lon As Decimal 

End Structure 

Function decodePoly(ByRef encoded As String) As List(Of LatLng) 
    Dim poly As List(Of LatLng) = New List(Of LatLng) 
    Dim index As Integer = 0 
    Dim len As Integer = encoded.Length() 
    Dim lat As Integer = 0 
    Dim lng As Integer = 0 

    While (index < len) 
     Dim b As Integer 
     Dim shift As Integer = 0 
     Dim result As Integer = 0 
     Do 
      b = AscW(encoded.Chars(index)) - 63 
      index += 1 
      result = result Or (b And &H1F) << shift 
      shift += 5 
     Loop While (b >= &H20) 
     Dim dlat As Integer    
     If (result And 1) <> 0 Then 
      dlat = Not (result >> 1) 
     Else 
      dlat = result >> 1 
     End If 
     lat += dlat 

     shift = 0 
     result = 0 
     Do 
      b = AscW(encoded.Chars(index)) - 63 
      index += 1 
      result = result Or (b And &H1F) << shift 
      shift += 5 
     Loop While (b >= &H20) 
     Dim dlng As Integer 
     If (result And 1) <> 0 Then 
      dlng = Not (result >> 1) 
     Else 
      dlng = result >> 1 
     End If 
     lng += dlng 

     Dim p As LatLng = New LatLng With {.Lat = (lat/100000.0), .Lon = (lng/100000.0)} 
     poly.Add(p) 

    End While 

    decodePoly = poly 

End Function 
+0

Non capisco come questa risposta aiuterà le persone a leggere una domanda taggata [android]. Usi VB su Android? –

+0

No, ma questo è l'unico posto che ho trovato che ha una routine decente per decodificare una linea poligonale. Il codice C# funziona in Windows senza modifiche. Forse qualcun altro arriva e trova questo che usa Windows, ne ha bisogno in VB. –

0

Ho pubblicato un simile answer to this question on another post per Android/Java. Decodifica il poly e restituisce Latlng invece di Geopoints.

+0

Questa domanda è vecchia ... Direi che è molto antiquata e non funziona più – Fustigador

+0

@Fustigador Quale parte non funziona più? Recentemente mi sono imbattuto in questo problema e ho trovato una soluzione. – Marlon

+0

Stavo solo supponendo, a causa del tempo che la mia domanda ha – Fustigador

0

Ecco l'implementazione in iOS, per chiunque sia curioso, che è interamente basato sulla risposta di @ Fustigador, ma convertita in iOS. Si noti che non ho formattato il codice di conseguenza. Ho solo aggiunto alcune variabili per il gusto di restituire l'oggetto promesso.

- (GMSPath *)decodedPolylinePathFromEncodedPolylineString:(NSString *)encodedPolylineString { 


    NSString *decodedPolylineString = @""; 
    GMSMutablePath *decodedPolylinePath = [GMSMutablePath new]; 
    CLLocationCoordinate2D decodedCoordinate; 
    CLLocationDegrees latitude, longitude; 

    int index = 0; 
    NSUInteger len = encodedPolylineString.length; 

    int lat = 0, lng = 0; 

    while (index < len) { 
     int b, shift = 0, result = 0; 
     do { 

      b = [encodedPolylineString characterAtIndex:index++] - 63; 
      result |= (b & 0x1f) << shift; 
      shift += 5; 
     } while (b >= 0x20); 
     int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); 
     lat += dlat; 

     shift = 0; 
     result = 0; 
     do { 
      b = [encodedPolylineString characterAtIndex:index++] - 63; 
      result |= (b & 0x1f) << shift; 
      shift += 5; 
     } while (b >= 0x20); 
     int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); 
     lng += dlng; 

     latitude = (((double) lat/1E5)); 
     longitude = (((double) lng/1E5)); 

     decodedCoordinate = CLLocationCoordinate2DMake(latitude, longitude); 

     decodedPolylineString = [NSString stringWithFormat:@"%f%f", latitude, longitude]; 
     ; 
     NSLog(@"%@",decodedPolylineString); 

     [decodedPolylinePath addCoordinate:decodedCoordinate]; 
    } 


    return decodedPolylinePath; 
} 
3

Stesso in Javascript

function decodePolyline(encoded) { 
     if (!encoded) { 
      return []; 
     } 
     var poly = []; 
     var index = 0, len = encoded.length; 
     var lat = 0, lng = 0; 

     while (index < len) { 
      var b, shift = 0, result = 0; 

      do { 
       b = encoded.charCodeAt(index++) - 63; 
       result = result | ((b & 0x1f) << shift); 
       shift += 5; 
      } while (b >= 0x20); 

      var dlat = (result & 1) != 0 ? ~(result >> 1) : (result >> 1); 
      lat += dlat; 

      shift = 0; 
      result = 0; 

      do { 
       b = encoded.charCodeAt(index++) - 63; 
       result = result | ((b & 0x1f) << shift); 
       shift += 5; 
      } while (b >= 0x20); 

      var dlng = (result & 1) != 0 ? ~(result >> 1) : (result >> 1); 
      lng += dlng; 

      var p = { 
       latitude: lat/1e5, 
       longitude: lng/1e5, 
      }; 
      poly.push(p); 
     } 
     return poly; 
    } 
8

Per coloro che hanno bisogno di questo ora, c'è una libreria open-source, con un sacco di cose utili per quanto riguarda l'API di Google Maps di Android, tra cui la decodifica e la codifica di polilinee.

Verificare a Android Maps Utils e Android Maps Util Github. per la decodifica e l'uso di codifica:

PolyUtil.decode(String encodedPath); 
PolyUtil.encode(List<LatLng> path); 
+1

Questo dovrebbe essere il modo corretto per andare invece di scrivere il decodificatore da solo. –

0

stesso in Pascal (Delphi):

var lat,lon,lat_f,lon_f:Double; 
    var index:Integer; 
    var len:Integer; 
    var b:Integer; 
    var shift:Integer; 
    var result:Integer; 
    var encoded:String; 
    var dlat:Integer; 
    var dlng:Integer; 

    encoded:='ibgqGq}ycIMvM'; 
    len:= Length(encoded); 

    lat:=0; 
    lon:=0; 
    While (index <=len) do 
    begin 
    b:=$20; 
    shift:=0; 
    result:=0; 
    While (b >= $20) do 
     begin 
     b:=ord(encoded[index]); 
     b:=b-63; 
     index:= index+1; 
     result:= result OR (b AND $1f) Shl shift; 
     shift:=shift + 5; 
     end; 

     If (result And 1) <> 0 Then 
     dlat:= Not (result Shr 1) 
     Else 
     dlat:= result Shr 1; 
     lat:=lat+dlat; 

     shift:= 0; 
     result:= 0; 
     b:=$20; 
     While (b >= $20) do 
     begin 
     b:=ord(encoded[index]); 
     b:=b-63; 
     index:= index+1; 
     result:= result OR (b AND $1f) Shl shift; 
     shift:=shift + 5; 
     end; 

     If (result And 1) <> 0 Then 
      dlng:= Not (result Shr 1) 
     Else 
      dlng:= result Shr 1; 
     lon:=lon+dlng; 
{ The coordinates of the point are used for our purposes } 
     lon_f:=lon/100000.0; 
     lat_f:=lat/100000.0; 
    end; //while 
0

Questo metodo è utile per la decodifica polyline

private List<LatLng> decodePoly(String encoded) { 
    List<LatLng> poly = new ArrayList<>(); 
    int index = 0, len = encoded.length(); 
    int lat = 0, lng = 0; 

    while (index < len) { 
     int b, shift = 0, result = 0; 
     do { 
      b = encoded.charAt(index++) - 63; 
      result |= (b & 0x1f) << shift; 
      shift += 5; 
     } while (b >= 0x20); 
     int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); 
     lat += dlat; 

     shift = 0; 
     result = 0; 
     do { 
      b = encoded.charAt(index++) - 63; 
      result |= (b & 0x1f) << shift; 
      shift += 5; 
     } while (b >= 0x20); 
     int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); 
     lng += dlng; 

     LatLng p = new LatLng((((double) lat/1E5)), 
       (((double) lng/1E5))); 
     poly.add(p); 
    } 

    return poly; 
} 

Questo è come mi sto polyline

JSONObject poly = route.getJSONObject("overview_polyline"); 
String polyline = poly.getString("points"); 
polyLineList = decodePoly(polyline); 
Problemi correlati