# Using JLink to decode GMap Polyline strings

I would like to use this java code inside Mathematica using JLink. It converts Google Maps API Encoded Polylines to a list of points. I tried the Mathematica tutorial but get 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
show 1 more comment

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.

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