/* ---------------------------------------------------------------- */ /* Decodes a Google encoded PolyLine string into latitude/longitude */ /* pairs */ /* ---------------------------------------------------------------- */ /* */ /* Originally by Ruurd J. Idenburg */ /* */ /* No copyright, no licence, no guarantees or warrantees, be it */ /* explicit, implicit or whatever. Usage is totally and completely */ /* at the users own risk, the author shall not be liable for any */ /* damages whatsoever, for any reason whatsoever. */ /* */ /* Please keep this comment block intact when modifying this code */ /* and add a note with date and a description. */ /* */ /* ---------------------------------------------------------------- */ /* Parameter(s): */ /* */ /* encodedPolyline - a polyline encoded in Google format. */ /* e.g. "_p~iF~ps|U_ulLnnqC_mqNvxq`@" */ /* */ /* Result: */ /* */ /* If invoked as a command latitude/longitude pairs to stdout, */ /* if invoked as a function latitude/longitude pairs into array. */ /* */ /* ---------------------------------------------------------------- */ /* 2013/12/13 - Initial version */ /* ---------------------------------------------------------------- */ --::routine decodeGString parse source os how me if how=="FUNCTION" then myResult = .array~new() numeric digits 20 parse arg encPoly -- get rid of surrounding spaces encPoly = encPoly~space(0) -- get rid of surrounding quotes if (encPoly~pos('"')=1 & encPoly~lastpos('"')=encPoly~length) then encPoly = encPoly~strip('B','"') if (encPoly~pos("'")=1 & encPoly~lastpos("'")=encPoly~length) then encPoly = encPoly~strip('B',"'") -- get rid of possibly escaped backslashes --encPoly = encPoly~changestr('\\','\') -- setup latitude and longitude latitude = 0 longitude = 0 -- first position in encoded string i = 1 do until i>=encPoly~length -- first the latitude result = '00000000'x byte = 32 do j=1 by 1 while (byte>=32) -- Convert each character to it's decimal value minus 63 byte = encPoly~subchar(i)~c2d-63 -- bitwise AND byte with '1F'x then shift left 5*(j-1) (i.e. multiply by 32**(j-1) -- and OR into 4 byte result. That is: 5 bit chunks concatenated in reverse order. -- The opposite of the encoding steps. result = ((byte//32)*(32**(j-1)))~d2c(4)~bitor(result) -- increment position in encoded string i += 1 --if i>=1550 then trace ?i end -- encoding used 2's complement for negative values -- if sign bit is not 0 then result should be negative if result~bitand('00000001'x)~c2d\=0 then deltalatitude = -(result~c2d/2)~format(,0)/1e5 else deltalatitude = (result~c2d/2)~format(,0)/1e5 /* if result~bitand('00000001'x)~c2d\=0 then testlatitude = latitude - ((result~c2d/2)~format(,0)/1e5) else testlatitude = latitude + ((result~c2d/2)~format(,0)/1e5) */ latitude += deltalatitude -- now the longitude result = '00000000'x byte = 32 do j=1 by 1 while (byte>=32) -- Convert each character to it's decimal value minus 63 byte = (encPoly~subchar(i)~c2d-63) -- bitwise AND byte with '1F'x then shift left 5*(j-1) (i.e. multiply by 32**(j-1) -- and OR into 4 byte result result = ((byte//32)*(32**(j-1)))~d2c(4)~bitor(result) -- increment position in encoded string i += 1 end -- if sign bit is not 0 then result should be negative if result~bitand('00000001'x)~c2d\=0 then deltalongitude = -(result~c2d/2)~format(,0)/1e5 else deltalongitude = (result~c2d/2)~format(,0)/1e5 /* if result~bitand('00000001'x)~c2d\=0 then testlongitude = longitude - (result~c2d/2)~format(,0)/1e5 else testlongitude = longitude + (result~c2d/2)~format(,0)/1e5 */ longitude += deltalongitude if how=="COMMAND" then say latitude longitude else myResult~append(latitude longitude) --if longitude==-74.88173 then trace ?i end if how=="FUNCTION" then return myResult