Decode a route shape

Mapzen Turn-by-Turn uses the encoded polyline format to store a series of latitude, longitude coordinates as a single string. Polyline encoding greatly reduces the size of the route response, especially for longer routes. A description is found here: polyline encoding.

Note that Mapzen APIs use six digits of decimal precision, rather than five as referenced in the Google algorithms documentation.

Below are some sample algorithms to decode the string to create a list of latitude,longitude coordinates.

JavaScript

Here is an example of decoding in JavaScript.

// This is adapted from the implementation in Project-OSRM// https://github.com/DennisOSRM/Project-OSRM-Web/blob/master/WebContent/routing/OSRM.RoutingGeometry.jspolyline.decode=function(str,precision){varindex=0,lat=0,lng=0,coordinates=[],shift=0,result=0,byte=null,latitude_change,longitude_change,factor=Math.pow(10,precision||6);// Coordinates have variable length when encoded, so just keep// track of whether we've hit the end of the string. In each// loop iteration, a single coordinate is decoded.while(index<str.length){// Reset shift, result, and bytebyte=null;shift=0;result=0;do{byte=str.charCodeAt(index++)-63;result|=(byte&0x1f)<<shift;shift+=5;}while(byte>=0x20);latitude_change=((result&1)?~(result>>1):(result>>1));shift=result=0;do{byte=str.charCodeAt(index++)-63;result|=(byte&0x1f)<<shift;shift+=5;}while(byte>=0x20);longitude_change=((result&1)?~(result>>1):(result>>1));lat+=latitude_change;lng+=longitude_change;coordinates.push([lat/factor,lng/factor]);}returncoordinates;};

C++ 11

Here is an example of decoding in C++11

#include<vector>constexprdoublekPolylinePrecision=1E6;constexprdoublekInvPolylinePrecision=1.0/kPolylinePrecision;structPointLL{floatlat;floatlon;};std::vector<PointLL>decode(conststd::string&encoded){size_ti=0;// what byte are we looking at// Handy lambda to turn a few bytes of an encoded string into an integerautodeserialize=[&encoded,&i](constintprevious){// Grab each 5 bits and mask it in where it belongs using the shiftintbyte,shift=0,result=0;do{byte=static_cast<int>(encoded[i++])-63;result|=(byte&0x1f)<<shift;shift+=5;}while(byte>=0x20);// Undo the left shift from above or the bit flipping and add to previous// since its an offsetreturnprevious+(result&1?~(result>>1):(result>>1));};// Iterate over all characters in the encoded stringstd::vector<PointLL>shape;intlast_lon=0,last_lat=0;while(i<encoded.length()){// Decode the coordinates, lat first for some reasonintlat=deserialize(last_lat);intlon=deserialize(last_lon);// Shift the decimal point 5 places to the leftshape.emplace_back(static_cast<float>(static_cast<double>(lat)*kInvPolylinePrecision),static_cast<float>(static_cast<double>(lon)*kInvPolylinePrecision));// Remember the last one we encounteredlast_lon=lon;last_lat=lat;}returnshape;}

Python

Here is an example of decoding in Python

#!/usr/bin/env pythonimportsys#six degrees of precision in valhallainv=1.0/1e6;#decode an encoded stringdefdecode(encoded):decoded=[]previous=[0,0]i=0#for each bytewhilei<len(encoded):#for each coord (lat, lon)ll=[0,0]forjin[0,1]:shift=0byte=0x20#keep decoding bytes until you have this coordwhilebyte>=0x20:byte=ord(encoded[i])-63i+=1ll[j]|=(byte&0x1f)<<shiftshift+=5#get the final value adding the previous offset and remember it for the nextll[j]=previous[j]+(~(ll[j]>>1)ifll[j]&1else(ll[j]>>1))previous[j]=ll[j]#scale by the precision and chop off long coords also flip the positions so#its the far more standard lon,lat instead of lat,londecoded.append([float('%.6f'%(ll[1]*inv)),float('%.6f'%(ll[0]*inv))])#hand back the list of coordinatesreturndecodedprintdecode(sys.argv[1])