Map View draw directions using google Directions API - decoding polylines
Asked Answered
T

4

12

I'm trying to use the Google directions API to show directions on my mapview but I am having difficulties getting the data from the JSON response. I can get the "levels" and "points" strings but can't work out how to decode them to points on the map.

Any help would be much appreciated.

Tressietressure answered 15/7, 2011 at 14:18 Comment(0)
P
20

I have a class which can decode them for you, add the class below then call in your code like this:

int[] decodedZoomLevels = PolylineDecoder.decodeZoomLevels(levels);
GeoPoint[] gPts = PolylineDecoder.decodePoints(points, decodedZoomLevels.length);

where points and levels are the data you've extracted from the JSON response. You can then go through the array of geopoints drawing a line between them to display your directions.

Hope this helps! Kenny


EDIT: It would seem that the google directions API no longer returns the zoom levels string as part of the JSON response, not to worry though, all we were using this for was to check the number of points, so we can simply put these into a list like:

public static List <GeoPoint> decodePoints(String encoded_points){
int index = 0;
int lat = 0;
int lng = 0;
List <GeoPoint> out = new ArrayList<GeoPoint>();

try {
    int shift;
    int result;
    while (index < encoded_points.length()) {
        shift = 0;
        result = 0;
        while (true) {
            int b = encoded_points.charAt(index++) - '?';
            result |= ((b & 31) << shift);
            shift += 5;
            if (b < 32)
                break;
        }
        lat += ((result & 1) != 0 ? ~(result >> 1) : result >> 1);

        shift = 0;
        result = 0;
        while (true) {
            int b = encoded_points.charAt(index++) - '?';
            result |= ((b & 31) << shift);
            shift += 5;
            if (b < 32)
                break;
        }
        lng += ((result & 1) != 0 ? ~(result >> 1) : result >> 1);
        /* Add the new Lat/Lng to the Array. */
        out.add(new GeoPoint((lat*10),(lng*10)));
    }
    return out;
}catch(Exception e) {
    e.printStackTrace();
}
return out;
}

EDIT: OLD CODE

public class PolylineDecoder {
/**
 * Transform a encoded PolyLine to a Array of GeoPoints.
 * Java implementation of the original Google JS code.
 * @see Original encoding part: <a href="http://code.google.com/apis/maps/documentation/polylinealgorithm.html">http://code.google.com/apis/maps/documentation/polylinealgorithm.html</a>
 * @return Array of all GeoPoints decoded from the PolyLine-String.
 * @param encoded_points String containing the encoded PolyLine. 
 * @param countExpected Number of points that are encoded in the PolyLine. Easiest way is to use the length of the ZoomLevels-String. 
 * @throws DecodingException 
 */
public static GeoPoint[] decodePoints(String encoded_points, int countExpected){
    int index = 0;
    int lat = 0;
    int lng = 0;
    int cnt = 0;
    GeoPoint[] out = new GeoPoint[countExpected];

    try {
        int shift;
        int result;
        while (index < encoded_points.length()) {
            shift = 0;
            result = 0;
            while (true) {
                int b = encoded_points.charAt(index++) - '?';
                result |= ((b & 31) << shift);
                shift += 5;
                if (b < 32)
                    break;
            }
            lat += ((result & 1) != 0 ? ~(result >> 1) : result >> 1);

            shift = 0;
            result = 0;
            while (true) {
                int b = encoded_points.charAt(index++) - '?';
                result |= ((b & 31) << shift);
                shift += 5;
                if (b < 32)
                    break;
            }
            lng += ((result & 1) != 0 ? ~(result >> 1) : result >> 1);
            /* Add the new Lat/Lng to the Array. */
            out[cnt++] = new GeoPoint((lat*10),(lng*10));
        }
        return out;
    }catch(Exception e) {
        e.printStackTrace();
    }
    return out;
}

public static int[] decodeZoomLevels(String encodedZoomLevels){
    int[] out = new int[encodedZoomLevels.length()];
    int index = 0;

    for(char c : encodedZoomLevels.toCharArray())
        out[index++] = c - '?';
    return out;

}
}
Peper answered 15/7, 2011 at 14:22 Comment(4)
hi Kenny, how can i get levels encoded string? or levels and points strings are same?Tidwell
llango J - It would seem they have removed it from the response so its just the points you get now. I've modified the code to work with just this one parameter, you should see it in the edited answer!Peper
Hi, now there is a new google map version and GeoPoint class doesn't support by new api. can i use LatLng(double lat,double lng) instead of GeoPoint(int, int)?Pledge
This produces an exception(StringIndexOutOfBoundsException) on line int b = encoded_points.charAt(index++) - '?' for second inner while loop, how to handle this? thanksLeah
G
6

You can use the Google Maps Android API Utility Library. It proposes a PolyUtil.decode(String encoded) method that does exactly what you need !

Goose answered 23/5, 2014 at 12:51 Comment(0)
H
0

GeoPoint doesn't work for me, I cant find the library that uses it. Here is a function that returns LatLng values instead.

public static ArrayList<LatLng> decodePolyPoints(String encodedPath){
    int len = encodedPath.length();

    final ArrayList<LatLng> path = new ArrayList<LatLng>();
    int index = 0;
    int lat = 0;
    int lng = 0;

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

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

        path.add(new LatLng(lat * 1e-5, lng * 1e-5));
    }

    return path;
}

Grabbed it from Google Maps Android API utility library. Code can be found here

Some reminders when testing this with hard coded strings in the code, Java cannot correctly read

"\"

you need to add another slash for it to be correctly read by java.

"\\"

Just a heads up because encoded strings contain weird characters.

Hemorrhage answered 29/9, 2015 at 8:0 Comment(0)
B
0

below code decode any encoded 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=0, shift = 0, result = 0;
        do {
            if(index<len) {
                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 {
            if(index<len) {
                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;
}
Babism answered 11/5, 2021 at 11:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.