Hacking Google Maps


A word of warning: this is a particular aloof entry, because it’s for my own interest more than anything else. Sorry if it makes no sense to anyone else. 🙂

I’ve spent quite a bit of time trying to find some software to do flight mapping for the UAV, so I can avoid writing it myself. 🙂 Unfortunately, I just can’t find anything that’s free, let alone cross-platform. There’s certainly a few things out there, but they’re either just out of the question ($$$) or simply don’t work properly. Or are so simple that they’re not worth the effort – e.g. OziExplorer, which requires you to manually import maps and whatnot. And it’s expensive if you want actual 3D.

What would be nice would be to use Google Earth, perhaps with some plugins or whatnot. Sadly, the free version of Google Earth doesn’t let you draw paths or import GPS data. Even if you go right up to the $400-a-pop Pro version, there doesn’t seem to be any way to vary the altitude of points within the same path… so you’re just doing 2D mapping, which is trivial anyway. D’oh.

But I still want that map data… 🙂

So, I’ve begun hacking at the Google Maps AJAX API. At this point I’m ecstatic that we in MacOS-land have WebKit, which allowed me to get the basic mapping up and running in about 10 minutes, nine and a half of which were me causing exceptions because of my naive use of NSStrings (instead of NSURLs).

Anyway, I’ve now spent about a whole day’s worth on it, and have got a bit of a grasp on the HTML DOM and JavaScript. The last time I used JavaScript was probably to make annoying status bar animations… hopefully those websites have long since died. 🙂

Anyway, I’ve had some luck poking at it. The API of course doesn’t really want you to thieve off with it’s images. Sure, you can, but aligning them with their GPS co-ords isn’t entirely trivial. And getting the exact one you want, given a lat/long, isn’t straight-forward either.

One problem is that while the street & border map layer has a very nice URL scheme, which refers to each tile by X & Y index, the satellite imagery uses some kind of obfuscation. This isn’t such an issue, as there’s a function buried deep within Google’s JavaScript API for getting the URL for any layer given the tile index, but still.

The next problem is that there’s not actually a proper or easy way to determine the index of any particular tile, given a lat/long or even the position of the image within the DIV. My current thought is to decode those from the street & border map URLs, but it’s messy. I’m sure there’s hidden SPI for doing what I want, since I’m sure some elements of the system would need to do what I’m wanting, but of course it’s not exposed and the raw JavaScript is obfuscated, and I’m not sure I can be bothered trying to decode it.

I’ve also been trying to figure out if I can determine the lat/long from the index myself… while I seem to have gotten the longitude correct, it seems the latitude isn’t linear… while I got the correct longitude for my test site, Stanford University, I ended up somewhere in the middle of Canada because the latitude was way off. I haven’t actually confirmed that it’s non-linear, but I don’t see any other explanation… if it were linear, to fit my results Google Maps would only cover plus/minus 60 degrees latitude, contrary to it’s very convincing appearance of covering the full 180.

But then, all this may not actually be necessary. For testing I’m trying to pull out the exact tile for a given lat/long, but really, the solution for the real program is probably simpler: centre the map on the desired lat/long using it’s JavaScript API, then just cache every image it pulls down. By enumerating the childNodes of each mapping layer, I can get the URL alongside it’s position in the DIV, and I can use that position to determine the lat/long bounds of the tile. It’s then just a matter of panning around the map as necessary to get more and more edge tiles. Not directly reliable, but probably functional.

So I think it can be done, one way or another… but it’ll probably take a good day of coding just to implement all I’ve just described all-too-deceptively-succinctly in one paragraph, since the whole thing’s all asynchronous and I haven’t quite tested how I can actually get the images themselves (well, I can get the URLs, so presumably it’s just a matter of issuing a NSURLRequest in the worst case)… lots of work ahead, it seems.

At least the other major task I’ve been working on, the I/O system for the AVR, is more or less done now. At least, until we get some boards made to actually test on; then I’ll have to actually make it work, and all that extra gloss… 😉

Anyway, I’ll leave for now with an image of my hackery, showing our current UAV test centre. 😉 The text fields at the bottom are for evaluating JavaScript in the view, which I quickly realised was a way better solution than using NSLog and recompiling and re-running for every test. (!!) 🙂

I really wish WebView’s JavaScript eval method would actually give some useful debug output, though; returning nil really doesn’t help much for a complex expression.

Picture 4

Leave a Reply