I would like to use this java code inside Mathematica using J/Link. It converts Google Maps API Encoded Polylines to a list of points. I tried the Mathematica tutorial but got lost.

There is the Java code:

private List<GeoPoint> decodePoly(String encoded) {

List<GeoPoint> poly = new ArrayList<GeoPoint>();
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;

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

}

return poly;
}


As example:

wjiGtdpcNrAlBJZ


should return

43.64175, -79.38651
43.64133, -79.38706
43.64127, -79.3872


I have no experience in Java. The code came from here.

• This answer by Leonid is exactly what you want. – rm -rf Oct 3 '12 at 22:01
• I sow the post, tks. But it do not worked (the original post test code worked). I just replaced the code above in the argument jlcsCode and tried to compile it. I should have done something more? – Murta Oct 4 '12 at 2:39
• Leonid's code tests for the presence of a class, and this is only a function. Also, if it were a class, we would still need access to the GeoPoint class, and I have no idea where to get it. Lastly, Mark McClure has Mathematica code to do perform the decoding, so you could use his – rcollyer Oct 4 '12 at 4:15
• @rcollyer Actually, my Mathematica code only encodes polylines, rather than decoding them. The decoding scheme is bitwise operation based and would likely be a pain to translate. I responded with instructions on accessing a Java class, though. – Mark McClure Oct 4 '12 at 8:06
• Also, I believe the GeoPoint class is part of Google's Android map development kit, which seems a bit heavyweight if you just want to decode a polyline. – Mark McClure Oct 4 '12 at 8:08

Comment

I've placed a Notebook version of this post on my webspace here: http://facstaff.unca.edu/mcmcclur/polylineDecoder.zip

The Notebook is actually contained in a ZIP file that also contains all the Java class files necessary to get this code to work. The Notebook sets the Java class relative to it's own directory using AddToClassPath[NotebookDirectory[]], so everything should just run without difficulty.

Here's my preferred java polyline decoder: https://github.com/scoutant/polyline-decoder

The advantage of this version is that it is self-contained, while Jeffery's depends on a GeoPoint class defined in a rather large SDK.

After compiling the files in src/main/java/org/scoutant/polyline, you can use the decoder like so:

Needs["JLink"];
InstallJava[];
polylineDecoder = JavaNew["org.scoutant.polyline.PolylineDecoder"];
decoded = polylineDecoder@decode["wjiGtdpcNrAlBJZ"];
length = decoded@size[];
Table[
point = decoded@get[k];
{point@getLat[], point@getLng[]},
{k, 0, length - 1}]

(* Out:
{{1.3638, -79.3865}, {1.36338, -79.3871}, {1.36332, -79.3872}}
*)


While the latitudes all disagree with your expected result, it agrees with my javascript decoder: http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/decode.html

An example using imported directions

As a fun example, we could download some driving directions from Google Maps, extract the encoded polyline string, and display it on a CountryData map.

Needs["JLink"];
InstallJava[];
polylineDecoder = JavaNew[
"org.scoutant.polyline.PolylineDecoder"
];
jsonString = StringDrop[Import[
], 9];
json = ImportString[jsonString, "JSON"];
polylines = "polylines" /.
Cases[json, HoldPattern["polylines" -> _], Infinity];
pointStrings = Table["points" /. polyline, {polyline, polylines}];
pointString = First[pointStrings];
pointString = StringReplace[pointString, "\\\\" -> "\\"];
decoded = polylineDecoder@decode[pointString];
length = decoded@size[];
pts = {#@getLng[], #@getLat[]} & /@ decoded@toArray[];
Show[{
CountryData["UnitedStates", {"Shape", "Equirectangular"}],
Graphics[{{Blue, Line[pts]},
{PointSize[Large], Green, Point[First[pts]], Red,
Point[Last[pts]]}}]
}] • Tks Mark!. Very good post, exact what I need. Just one more question: I download the file "scoutant-polyline-decoder-76406ba" from github as you pointed, but how I compile it to use in Mathematica? It's using "ReinstallJava[ClassPath -> "~/MyJavaDir/MyPackage.jar:~/MyJavaDir"]" ? Some clue? I use Mac OS. – Murta Oct 4 '12 at 11:32
• @Murta Awesome! If you use Mac OS, open the terminal application (Go menu -> Applications, then terminal is in Utilities). You should get a command line interface. Use the cd command to get to the polyline directory and then type "javac *". If you have a java compiler, which you might, then this should generate java class files. If not, you can get one by installing XCode. If that's all a bit too much, I'd be happy to compile and post the executables with a working notebook in a ZIP file. – Mark McClure Oct 4 '12 at 11:40
• HI @Mark. I compiled it, and 3 .class files where created together with pre existent .java. Sorry, but I don't know how to connect it with your first code. The notebook is welcome. Tks in advance! – Murta Oct 4 '12 at 12:13
• @Murta If you've got the .class files, then you should be ready to go! The only issue I can imagine is at the AddToClassPath step. The easiest thing to do would be to save your working notebook right into the scoutant-polyline-decoder-76406ba directory. (I wonder if the "76506ba" is randomly generated?). Then the AddToClassPath call should be AddToClassPath["src/main/java/"]. I'll probably create the notebook anyway, but not until later. – Mark McClure Oct 4 '12 at 12:22
• Also, note that I've made some edits to the code in the post to fix a couple of errors. – Mark McClure Oct 4 '12 at 12:23

I recently implemented a native Mathematica decoder for the encoded Google polyline strings returned during a request to its API. This uses Compile and I found it faster than the above J/Link based solution. I guess it could have been even faster if we could compile the BitShiftLeft and BitShiftRight. But I guess these two functions are pretty optimized in Mathematica. My compiled version for these two functions were slower so decided to stick with the built-ins.

### The decoder:

Clear[Com];
Com = Compile[ {{barray, _Integer, 1}},
Module[ {index = 1, lat = 0, lang = 0, latlng = {{0., 0.}}, b,
shift, result, dlat, bRight},
While[index <=  Length@barray,
b = shift = result = 0;
b = -63 + barray[[index++]];
result = BitXor[result, BitShiftLeft[BitAnd[b, 31], shift]];
shift += 5;
While[b >= 32,
b = -63 + barray[[index++]];
result = BitXor[result, BitShiftLeft[BitAnd[b, 31], shift]];
shift += 5;];
bRight = BitShiftRight[result, 1];
lat += If[BitAnd[result, 1] > 0, BitNot[bRight], bRight];
shift = result = 0;
b = -63 + barray[[index++]];
result = BitXor[result, BitShiftLeft[BitAnd[b, 31], shift]];
shift += 5;
While[b >= 32,
b = -63 + barray[[index++]];
result = BitXor[result, BitShiftLeft[BitAnd[b, 31], shift]];
shift += 5;];
bRight = BitShiftRight[result, 1];
lang += If[BitAnd[result, 1] > 0, BitNot[bRight], bRight];
AppendTo[latlng, {lang*10.^-5, lat*10.^-5}];
]; latlng], RuntimeOptions -> "Speed", CompilationTarget -> "C",
RuntimeAttributes -> {Listable}
, CompilationOptions -> {"ExpressionOptimization" -> True}
];
barray = ToCharacterCode@encoded;
(Rest@Com[barray])
];


### Utility Function:

Lets take a route connecting several cities given as a list.

route2 = {"Vienna,Austria", "Erlangen,Germany","Nurnberg,Germany","Heilbronn,Germany",
"Heidelberg,Germany", "Mannheim,Germany","Ludwigshafen,Germany", "Berlin,Germany"};


Here is a function that takes routes like above as input and forms the API request URL and do a respective data fetch from Google. For free users the map API serves up to 11-13 way-points requests in one single call.

UrlData[route_?(VectorQ[#, StringQ] &)] /; (2 <=  Length@route < 11) :=
Block[{WaypointSeperatorPosition, url, urlData, encoded},
WaypointSeperatorPosition =
Transpose@{1 + Range[-2 + Length@route]};
"?origin=" <> First@route <>
"&destination=" <> Last@route <>
"&waypoints=" <>
StringJoin[Most@Insert[route[[2 ;; -2]], "|", WaypointSeperatorPosition]] <>
"&sensor=false&mode=driving&units=metric";
URLFetch[url]
];


### Testing:

Now we can test our decoder to extract the longitude and latitude pairs of each points that constitute the Google polyline.

dat = UrlData[route2];
strings=(Flatten@(
ImportString[dat,{"JSON","Data","routes",1,"legs",All,"steps",All,"polyline","points"}]));
res = MathematicaDecode[#] & /@strings; // AbsoluteTiming


{2.685532, Null}

res1 = With[{pointString = #},
decoded = polylineDecoder@decode[pointString];
pts = {#@getLng[], #@getLat[]} & /@ decoded@toArray[];
pts] & /@ strings; // AbsoluteTiming


{9.156631, Null}

Both the results agree with each other.

Norm@(Chop@(Flatten[res1, 1] - Flatten[res, 1]))


0

### Visualize:

Here goes the route from Vienna to Berlin. With all the points on the polygon one could compute the road curvature/bending at each subsequent stretches on the polyline. • What about the code for the beautiful figure in the end? :) – Öskå Dec 13 '13 at 16:30