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

All content © Ruurd Idenburg, 2007–2025, 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 my on server at my home, falling under Dutch (privacy) laws.

This page updated on Wed, 28 May 2025 10:38:18 +0200.