Skip to content

Instantly share code, notes, and snippets.

@serialc
Last active January 22, 2018 22:03
Show Gist options
  • Save serialc/3a8ab85df9eb0cec7177f2b4bd13a1cd to your computer and use it in GitHub Desktop.
Save serialc/3a8ab85df9eb0cec7177f2b4bd13a1cd to your computer and use it in GitHub Desktop.
A google maps points decoder function in R
# Decode Google encoding lat,long point series
# Based on JavaScript code by Mapbox on Github: https://github.com/mapbox/polyline/blob/master/src/polyline.js
# Google algorithm: http://code.google.com/apis/maps/documentation/polylinealgorithm.html
decode_google_path <- function( point_string ) {
# break string into individual characters
chars <- strsplit(point_string, '')[[1]]
# get the utf8 integer representation of that character
# only characters from 64 onwards are used (@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~)
value <- sapply(chars, utf8ToInt) - 63
# Those values smaller than 32 (0x20 in hexadecimal) are the end of a lat or long data piece
# define groups
groups <- cumsum( !bitwAnd(value, 0x20) != 0 )
# need to shift the group delimiter back by one and drop the last value to be aligned properly
groups <- c(0, groups[-length(groups)])
# group lat/lngs together
llpair <- as.integer(groups/2)
# get the five right-most bits only of values
value <- bitwAnd(value, 0x1F)
# go through each lat/lng pair and 'stack' multiple integers into individual lat and long values
latlng <- data.frame(t(sapply(split(data.frame(value, groups), llpair), function(ll) {
# separately process the lat and long (in the same way)
result <- sapply( split(ll$value, ll$groups), function(l) {
# each value refers to a different magnitude that are all summed
sum(bitwShiftL(l, 0:(length(l) - 1) * 5))
})
# odd number require a different operation
odd <- sapply(result, bitwAnd, b=1) == 1
# if odd, shift bits right (divide by 2) and invert all bits (make negative and -1)
result[odd] <- bitwNot(bitwShiftR(result[odd], 1))
# if even, shift bits right (divide by 2)
result[!odd] <- bitwShiftR(result[!odd], 1)
result/10^5
})))
path <- sapply(latlng, cumsum)
colnames(path) <- c('lat', 'lng')
return(path)
}
# small test (6 lat, long pairs)
decode_google_path("qchrHadg]\\?^FtBVfCEfGuA")
# big test (313 lat, long pairs)
decode_google_path("cw_sHehu\\^Bl@D`@JbA^t@P~ANSnBgBlKgKE{CKIwDHsAZuCL{@ASHcACc@qAyGUwAAMDEDQFi@Ac@Gc@K[GI?MGSQ_@G[AyBEg@BaBr@yFnAcHj@aClB_HhCeJXWp@sAp@iABe@As@QiF]yIKsFW}HI{DDa@DQAg@EOIMSqFWkIG{B[wGa@uFc@gFu@oGk@cDi@aCWeAy@cC_AiB{DoGyIuN}DqGuCqEAE?CCECC@QMe@COIIE?MWMI][gKiQuA_CBM@YAWM_@IKECD[HS~GsFtBcCfAgAd@c@v@aAlOkJtG{DxIoFdFwCjKkGtA}@v@i@|CgBlI}ErTiMxGaEjLsHvCqBpF{DhIkG|JaIf\\gXpHcGjGeEbH_EzC{ArCsAlGgCzFoBhCu@tEiArJsBjXaGhEaAVJL?vQkBtAKhD]PGd@jAhAfCV^`EhDn@f@DRNTPL?D?H@HDNJHJ?JIFO@UAIN_@DQdB}Cz@}AdFaJrCaF`D{FxF_LpTka@b@g@vBuDnFyJjBiDdIcO|IgPvAaCrD_HjE_I~GcMhCiElBmDb@?|c@TxDAbFq@hBa@fZqIjAc@f@Kj@Eb@Bh@T`Ap@`KxHzCxBrAn@f@JvAj@xBfAlAb@dA`@bBf@z@Cf@I`@O^c@xA}Al@g@`@QpD{@AQrDwAL`@P^PTPH|@NPBNHVh@PdA\\fCTrATx@P`@Hn@@HDDB?FADKd@GxBBd@CxCo@fAWz@Cx@BzBNpCQxEo@PGnBmAnCgC~@aALA~@Hn@`@nCfD\\Zr@XbIhBv@L^BpBC`HCz@JtBpBhA|@d@HvES\\Bn@HnDdA^Dh@?l@Nt@l@f@j@d@`@^Rv@P~@@tAKv@Fp@Vv@`@h@lCV~@\\d@rBjBZFjCxBzB~A\\J`BFjFAx@O`@C|Bh@`AGl@Gd@S\\]RUd@Wp@WT?D?BFDJ?RGrBFpAHTf@p@z@dCvApEzAlENJlAKzCJRFJJFJ@XUx@\\?^FtBVfCEfGuA")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment