1: #!/usr/bin/env rexx
/* ---------------------------------------------------------------- */
/* Encodes a Google PolyLine string from 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): */
/* */
/* A series of latitude/longitude pairs separated by at least */
/* 1 space, either via: */
/* stdin - if invoked as a command */
/* or: */
/* an Array if invoked as a function/subroutine. */
/* */
/* Result: */
/* */
/* If invoked as a command encoded string to stdout, */
/* if invoked as a function the encoded string is return value. */
/* */
/* ---------------------------------------------------------------- */
/* 2013/12/13 - Initial version */
/* 2023/06/14 - Changed tmpWords from d2c to d2x as a tab char for */
/* instance is whitespace causing incorrect encoding */
/* ---------------------------------------------------------------- */
--::routine encodeGString
parse source os how me
if (how="COMMAND") then do
item = .input~supplier
end
else do
use strict arg thePath
if thePath~class~id<>"Array" then do
raise syntax 40.912 array("encodeGString",1,thePath~class~id)
end
item = thePath~supplier
end
numeric digits 20
prevLat = 0
prevLon = 0
encodedGString = ''
do while item~available
parse value(item~item) with lat lon .
-- no checking on valid range, maybe later if necessary
deltaLat = lat-prevLat
deltaLon = lon-prevLon
prevLat = lat
prevLon = lon
encodedGString = encodedGString || encodeDegrees(deltaLat)
encodedGString = encodedGString || encodeDegrees(deltaLon)
item~next
end
if how="COMMAND"
then say encodedGString
else return encodedGString
exit
encodeDegrees: Procedure
parse arg degrees
-- take the inital signed value, multiply by 1e5 and round the result
tmpString = (degrees*1e5)~format(,0)
-- convert to binary, left shift 1 position for sign bit
tmpString = (tmpString*2)~d2c(4)
-- if original was negative invert what we have
if degrees<0 then tmpString = tmpString~bitxor('ffffffff'x)
-- break this binary value out in 5 bit chunks from the right
-- and place them in reverse order
tmpString = tmpString~c2d
tmpWords = ''
do while tmpString>0
tmpWords = tmpWords (tmpString//32)~d2x(2)
tmpString = tmpString%32
end
-- OR each chunk with '20'x except the last, to indicate end of number
-- convert each chunk to decimal, add 63, concatenate into ascii string
encodedDegrees = ''
do i=1 to tmpWords~words-1
encodedDegrees = encodedDegrees || (tmpWords~word(i)~x2c~bitor('20'x)~c2d+63)~d2c
end
encodedDegrees = encodedDegrees || (tmpWords~word(i)~x2c~c2d+63)~d2c
return encodedDegrees