ooRexx logo
   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

If you feel inclined to make corrections, suggestions etc., please mail me any.
All content © Ruurd Idenburg, 2007–, except where marked otherwise. All rights reserved. This page is primarily for non-commercial use only. The Idenburg website records no personal information and sets no ‘cookies’. This site is hosted on a VPS(Virtual Private System) rented from Transip.nl, a Dutch company, falling under Dutch (privacy) laws (I think).

This page updated on by Ruurd Idenburg.