Декодирование полилинии с помощью нового API Карт Google
Я рисую маршрут между двумя точками на карте. Я получаю очки таким образом:
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;
Получаю ответ от Google и получаю 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);
Ответ, который я получаю от google: (в формате 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
И, наконец, я декодирую полученную строку таким образом, в которой я нашел множество ответов здесь, в 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;
}
Здесь я думаю, что ошибка есть, потому что я установил for для того, чтобы видеть точки, которые декодируются, и ответ выглядит примерно так:
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, эти пункты плохо разбираются. В результате ни одна нить не тянется.
Мой вопрос: кто-нибудь знает, как разобрать ответ от Google, и перевести его в объекты LatLng (НЕ объекты GeoPoints)?
Спасибо!
EDIT:
Это строка, которая должна быть расшифрована:
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]
Если с формированием LatLng вы подразумеваете способ создания объектов LatLng, вы можете увидеть в методе decodePoly. Эти объекты latLng добавляются к объектам PolylineOptions, и это добавляется к карте, таким образом:
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);
Ответы
Ответ 1
Я изменил decodePoly, который я использовал для этого, который я нашел после длительного поиска в Google, и теперь маршрут правильно нарисован.
http://wptrafficanalyzer.in/blog/route-between-two-locations-with-waypoints-in-google-map-android-api-v2/
Изменение
LatLng p = new LatLng((int) (((double) lat /1E5)* 1E6), (int) (((double) lng/1E5 * 1E6)));
для
LatLng p = new LatLng((((double) lat / 1E5)),(((double) lng / 1E5)));
И теперь работает.
Ответ 2
Для тех, кому это нужно сейчас, есть библиотека с открытым исходным кодом, в которой есть много полезного материала, касающегося API Android Карт Google, включая декодирование и кодирование полилиний.
Откажитесь от Android Maps Utils и Android Maps Util Github.
Для декодирования и кодирования используйте:
PolyUtil.decode(String encodedPath);
PolyUtil.encode(List<LatLng> path);
Ответ 3
То же самое в 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;
}
Ответ 4
Вот ваша функция в Visual Basic, которую я часто использую.
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
Ответ 5
Я отправил аналогичный ответ на этот вопрос в другом сообщении для Android/Java. Декодирование поли и возвращаемого Latlng вместо Geopoints.
Ответ 6
Вот реализация в iOS для любого, кто любопытен, который полностью основан на ответе @Fustigador, но преобразован в iOS. Обратите внимание, что я не форматировал код соответствующим образом. Я только добавил некоторые переменные ради возврата обещанного объекта.
- (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;
}
Ответ 7
То же самое в Паскале (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
Ответ 8
Этот метод полезен для декодирования полилинии
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;
}
Вот как я получаю полилинию
JSONObject poly = route.getJSONObject("overview_polyline");
String polyline = poly.getString("points");
polyLineList = decodePoly(polyline);