Decode Google Map encoded points as Well Known Text (WKT) with Python
I had close encounter of the 5th kind yesterday.. here’s the gist..
It started when someone “gave” me a GIS dataset (..of polygons, kind of..) that a colleague of theirs, way back in ancient history, chose to pre-cook as ASCII-encoded point pairs. Their intention was almost certainly to use the pre-cooked data in Google Maps. Anyway, being arguably sane, I wanted to return this data to a more GIS-normal format so I could put it in a database like MySQL or Post and use it for other stuff.
I considered a few different approaches to this problem, including creating a Google Map that could load-in all of the polygons from their encodings, then iterate over the polygons, interrogate the polygon point pairs, and finally concatenate WKT features from the points and save the geofeatures into a MySQL table. This approach offered the advantage of using Google’s existing Maps API to do the decoding for me. But let’s face it, that’s lame, uninspired, and not inventive.. it wasn’t even interesting.
Besides.. I wanted to use Python.
I expected to find a Python recipe for this looming in the misty www, but I didn’t. However, I did find a JavaScript recipe by trolling around in Mark McClure’s website. Specifically, he provides a Polyline Decoder utility, and when I viewed the page source, I found the JavaScript code that actually does the decoding (opening in FireFox will show you the code, or IE should prompt you to download the file).
Long story short, the following Python method is an adaptation of Mark McClure’s JavaScript method (twisted a little to return WKT features rather than the pure point array). If you’re somewhat comfortable with Python, you should be able to copy/paste the method right into your Python file and start calling it; just pass-in the encoded point string and let the method do the rest.
Best / Elijah
———
def decodeGMapPolylineEncoding(asciiEncodedString): print "\nExtrapolating WKT For:" print asciiEncodedString strLen = len(asciiEncodedString) index = 0 lat = 0 lng = 0 coordPairString = "" # Make it easy to close PolyWKT with the first pair. countOfLatLonPairs = 0 firstLatLonPair = "" gotFirstPair = False while index < strLen: shift = 0 result = 0 stayInLoop = True while stayInLoop: # GET THE LATITUDE b = ord(asciiEncodedString[index]) - 63 result |= (b & 0x1f) << shift shift += 5 index += 1 if not b >= 0x20: stayInLoop = False # Python ternary instruction.. dlat = ~(result >> 1) if (result & 1) else (result >> 1) lat += dlat shift = 0 result = 0 stayInLoop = True while stayInLoop: # GET THE LONGITUDE b = ord(asciiEncodedString[index]) - 63 result |= (b & 0x1f) << shift shift += 5 index += 1 if not b >= 0x20: stayInLoop = False # Python ternary instruction.. dlng = ~(result >> 1) if (result & 1) else (result >> 1) lng += dlng lonNum = lng * 1e-5 latNum = lat * 1e-5 coordPairString += str(lonNum) + " " + str(latNum) if gotFirstPair == False: gotFirstPair = True firstLatLonPair = str(lonNum) + " " + str(latNum) countOfLatLonPairs += 1 if countOfLatLonPairs > 1: coordPairString += "," # The data I was converting was rather dirty.. # At first I expected 100% polygons, but sometimes the encodings returned only one point. # Clearly one point cannot represent a polygon. Nor can two points represent a polygon. # This was an issue because I wanted to return proper WKT for every encoding, so I chose # To handle the matter by screening for 1, 2, and >=3 points, and returning WKT for # Points, Lines, and Polygons, respectively, and returning proper WKT. # # It's arguable that any encodings resulting in only one or two points should be rejected. wkt = "" if countOfLatLonPairs == 1: wkt = "POINT(" + coordPairString + ")" elif countOfLatLonPairs == 2: wkt = "POLYLINE(" + coordPairString + ")" elif countOfLatLonPairs >= 3: wkt = "POLYGON((" + coordPairString + "," + firstLatLonPair + "))" return wkt
this piece of code just made my life much simpler!
Thank you so much 🙂
newbieUser
25 Aug 14 at 2:26 pm edit_comment_link(__('Edit', 'sandbox'), ' ', ''); ?>
Excellent, I’m glad you could make use of it! /E
elrobis
27 Aug 14 at 9:12 am edit_comment_link(__('Edit', 'sandbox'), ' ', ''); ?>