Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decoding polyline with new Google Maps API

I am drawing a route between two points in a map. I receive the points this way:

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;

I receive the response from Google, and get the 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);

The response I get from google: (in JSON format):

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":"ecxuFjamUs@C"},"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":"ydxuFfamUPkG@a@JuGGk@"},"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":"adxuFvmlURQl@e@zAoATSTMf@]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`skU@?@@@@@?@@@?FBD?F@FAFAFADEDCFGDGDIBI@I@K@KAI?IAGAGAGCGCC?ACEEEIGGEICI?I?G@IBGD"},"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":"ucwuFjnkUo@}A_AcCiEeLKYq@mBYq@[o@u@kB?KAQ]aAI[EQQu@Gc@QwAM_BEa@AU"},"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\\CjIg@nBKD?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}iUzKgBvCe@t@KvGm@hDUbAMPCZElAM|D_@^En@EjBEd@Df@DnAD"},"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":"{duuFntiUFHB@^PDBFFFDDFDFBDDFBH@BBJ@F@H?F@H?FAH?FAF?FADAFAFCDADADEFCFEDEDEDEBEBEBGBE@G@E@G?G?EAG?GCGAGCEEGEEEEEEGEICIEIAKCKAK?K?MDgA?G?E?KJq@BODY@CBODW?C@I@AFe@F_@V{An@gED[@C?EHe@Ho@@G?A^{BjA}HF[tAiGzBwIdAcEVgApAuFr@sEF]Ju@DW?EDUHa@f@qEFo@f@iGXmHDgFCgGG{DM

And finally, I decode the received string this way, which I found in plenty of answers here in Stack Overflow:

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

This is where I think the error is, because I set a for to see the points that are being decoded, and the answer is something like:

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, these points are badly parsed. The result is, no line drawn anywhere.

My question is... does anybody know how to parse the answer from Google, and translate it to LatLng objects (NOT GeoPoints Objects)?

EDIT:

This is the String that is about to be decoded:

04-10 13:50:51.608: I/Location(25065): String to decode: gcxuFjamUq@CPkGLwHJ}@hCuBdEeDf@SrJuHnG{Ed@Fr@q@AmAm@k@e@DaIaSiEuLqAwJ~Mw@~ZwDtZuC`FKbCVjA`ANdAs@nBw@Py@]c@oAT}DhC{PlBcM~GaY|DyS`BmPRy]yBu\UsNvAqObAuEnC}KpAqIh@gK[}NcByWXoRt@}GlDeWvFcq@nFi`@~G}\|@aDdDoLn`@}gAfe@upA`JyV|CiN~@uId@{ZyBwVkBmOwB{^AsNt@iWb@qYcCyS_DkPmAaK{@gRN{RbCkWrFgUbHmPxLsP|JwIpPwN|G}JfE}I|C_KlCsNvAwSFaQj@i]jCmXbHg\pIgSpGaLnN}P`JsHfVaNbQkHtZyIrOsCnTaCx\aA`i@b@nSRz]K`J{AxJiDfNkJjU{WbKkJpGeEpVkPpEiEzMcQjQw]nJyM~IoJ`IoKnH{NrOaWtIeJdNgNrLcPjKqOhIuI~MeJxKgErR{Cn]EjQkBjHqBfJeE|\yTlI_JvEqJxHsS|Xuc@~IeR|EiRr@kEz@sNOoL_B}Lk@mCsFgKkCoGwAsG]}N`CuO`D}GjHoHtFwC|HgBhFg@fJ}BtHaF~D_FjLqSfGqE|FcBnGEnEv@xK`BzNeAxQfAlJ{@jIwEjE}FvBuF|B{NtCsNrBgEdHiIdGuIxDoFpGkFhDaBrHyBbF[pHPlDg@jEuBnCkCtFgKjEqEfIcGpC{D|GoNdAcExAkSjBgDrCsBpDa@vHLfSAfBk@nE_F|Im`@tO_ZxCyEzJmKtHyElG_ClZeF|j@sIlQaD|EuChGkHnK{MdIsMfPwa@bDeJpD_RpFsz@nA}IrCqIrYoa@|BeGlEiYpD}HbKoRfCyKdBwUjEmo@zBkKzDyJvCeQdB}LJqGmAqQJ_Gx@uFtHkO`ImMfMmXtFySpCkXRuN]aYVoT~@}LxB{NvD{OjJaYbFsLnCcEtLoMfJyXzIiXbIiL~D_EzQcMjDeF|AcFhA_M`BkXpC_KjCsDnDeClQcHvEgElFqJfF_Jp\mWzd@k]`WkWlVy`@nOcTz`@_s@rP_ZbNkQ~Tu^jJaUhCuIpHgUrPi\zd@uq@~McQh\e]vTaU~KcF~KoGhG{KzF{HzGmDbDwBfDiEzB}GbEmTrBsHpCuFxe@oq@xb@el@tDgC`ZeJnXkHrKmB~EeB~C{A`Ce@bCUrBoAnAuGSqIn@yEhDeOrCuQ|A}EvAwFdDgAfGSrHUJ\p@Bj@_A|Ao@tCsD|C}Rj@wAdCuW~Ds]VCJw@OUpEc_@jDKbDwB

If with LatLng format you mean the way the LatLng objects are created, you can see in the decodePoly method. These latLng objects are added to the PolylineOptions objects, and the this added to the map, this way:

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);
like image 928
Fustigador Avatar asked Apr 10 '13 11:04

Fustigador


2 Answers

For those who need this now, there's an open-source library with a lot of useful stuff regarding the Google Maps Android API, including decoding and encoding of polylines.

Check it out at Android Maps Utils and Android Maps Util Github. For decoding and encoding use:

PolyUtil.decode(String encodedPath);
PolyUtil.encode(List<LatLng> path);
like image 191
CounterFlame Avatar answered Nov 09 '22 06:11

CounterFlame


I changed the decodePoly that I was using for this one I found after a long search in Google, and now the route is drawn properly.

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

Changing

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

for

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

And now works.

like image 29
Fustigador Avatar answered Nov 09 '22 05:11

Fustigador