Decoding Polylines from Google Maps Direction API with Clojure

January 17, 2016, 12:56 pm

My first crack at porting some imperative code to Clojure goodness.

I needed some code to turn the polyline points encoding you get back from Google Directions API. This stuff:

"overview_polyline" : {
            "points" : "_rtwFpgubMtBuGVNFPfAr@TNIVkB|FsBpG_C_BqA}@mGeEwH_FsDcCaGwDkNiJsJmG_SoMyByAzA}EPi@nA{Dp@qBtDdCLh@@VCT_@nAKLMBOAIG}@{Aq@eAWWOMIEWEY?UDYJi@]^w@|AcC|Ew@bBy@hCg@dBQ`AU~A_ChH_D|J_AzCc@rAwXl|@yLt_@k@hCSrBAtABp@LlALp@FPZ~@Tf@Z^X^jAx@PXRTrCxB~@`@lA^`@HVLv@j@n@h@`@Rb@Dl@Gl@WVQTU^w@PaA@gAKcAMa@Q]c@i@}@g@iDoAeDaAeDq@qC]i@Cg@@eAT[L[Vk@h@SZQ^_@bAeJ`XoAbEmB~GqAvDkDzIsFvNcAvCcFrRkBnHcE`Pq@~Bi@rAk@hA}@hA_@f@cAfAoDjDiAv@iB|@a@XoAf@iBj@yA`@aB{Dz@yCl@yAmE`A}Aj@qCjAuC~AkBnA_@ZcBxAoApA{BhCoBtCuJrOkAxAkBzCeH~KkAlBeMrR{I|M}CtEyBjD}EpHmLbQ{BdDiBvCUBMJy@l@g@VeAZs@HiABuKT_BEiBUaEkAcA]oCeAmAi@iCsAyCkBgEaDcCuBa@]kHgGkDyCQQOOG_@Fk@h@YfI_DxAi@vAg@^`@h@l@h@dL@v@Ef@Od@m@fAy@nBmAxCc@dAALAHQf@Qv@G^Et@@n@Fr@Z`BHlABnAp@Cj@Q"

I found Jeffrey Sambells' Java code here that does the job. I am just getting my teeth into writing Clojure for my day job at GoCatch, so I need a Clojure version. This is my first attempt. It's midnight and I haven't had a chance to check the line ends up on a map correctly, but it looks pretty good to me:

;; Port of the Java code to decode google polylines that I found here -> http://jeffreysambells.com/2010/05/27/decoding-polylines-from-google-maps-direction-api-with-java
(defn decode-next-result [encoded]
  ;; keep scanning through encoded till b>=0x20
  ;; returns the next latitude/longitude increment
  (loop [[current & rest] encoded shift 0 result 0]
    (let [b       (- (int current) 63)
          result  (bit-or result (bit-shift-left (bit-and b 0x1f) shift))
          shift   (+ shift 5)] 
      (if (>= b 0x20) 
        (do 
          ;; if we are encoding the next result then we 
          ;; must have more characters to scan
          (assert rest)
          ;; keep looking for our next result
          (recur rest shift result))
        ;; we found our next result 
        (let [return-value (if (not= (bit-and result 1) 0)
                             (bit-not (bit-shift-right result 1))
                             (bit-shift-right result 1))]
          [return-value rest])))))

(defn lat-lng-double [lat-lng-int]
  (/ lat-lng-int 1E5))

(defn path-for-encoded-polyline [encoded] 
  (loop [rest encoded lat 0 lng 0 results []]
    (if rest
      ;; if there is anthing in the encoded array
      ;; we should have two more results at least 
      (let [next-result       (decode-next-result rest)
            new-rest          (second next-result)
            next-lat-result   (+ lat (first next-result))
            next-result       (decode-next-result new-rest )
            new-rest          (second next-result)
            next-lng-result   (+ lng (first next-result))]
          ;; add our lat lng result to the results
          (recur new-rest next-lat-result next-lng-result (conj 
                                                            results 
                                                            {:latitude (lat-lng-double next-lat-result) 
                                                             :longitude (lat-lng-double next-lng-result)})))
      ;; we are done, return our results
      results)))

#_
(def example-polyline "pdymEssfy[rJhAlANNeALyBD{@XqFBW^_AZi@NMp@sAPu@Bk@Ce@Qs@uA_Di@{@u@oAi@kAYm@_@mASgBOgBAcC?sBKyBYkFCyD@q@XyDLu@pAsDzDyJ`AaCJa@He@Bq@FoCw@[aBcAMQm@a@eAw@k@]yBaAwBaAqAaA_@S}DmBwD{BuLeHQKu@y@}BiCIOoEaLaJmUSQKSa@sAe@wDK}@@[g@}Am@uAkBkEkCmGg@gAk@{AQk@e@wBo@yAcAyAs@aAgDqEYWSUYa@o@{AoDeKcAwCkBqGg@eCQyAGcBC{AHsCmCf@iD^iAx@}AdAcA|@w@rAmAlBaBt@a@t@Y|Bo@xAs@z@y@n@iAf@wANq@J}@FyAEgAIkBImB?s@DkAHu@eCVeDRiGF}FGiB[sBc@{Am@qBMu@MiBe@gNIwAUmAk@uCMcAU_FKcAe@aCw@uByA}BaAwAMUw@{AoAoCk@mAYi@eAuBmBuD_AuBMICCiB_EeCsFYu@Uu@c@yCo@}CAe@i@sBIc@K_ACaADyAr@iFvBgMbB_Kz@eFj@kD^}A`@uA`CiHPcABYB[Dq@@]Dg@eBZeAr@oAl@w@VUdBsAr@c@~CuBbC_Bn@]d@_@V]NUPa@Pq@Hs@@{@Cm@Ii@Ug@UcA_@kAo@uCqAeHg@kCSi@GK]uAUs@OWEGSYQQk@e@}@a@c@Kc@AiBQiAA[CiC?GAwBAUAu@USI[UQ[GMMk@EqBG_DKsCCcBJcDcCIuBK")
#_
(path-for-encoded-polyline (seq (char-array example-polyline)))


Permalink - Comments - Tags: Development,Clojure

Hundreds Chart Dev Diary

June 28, 2015, 12:32 am

I've had this idea for a game to teach kids times tables since I finished Wordflight two years go. I got bogged down in my initial implementation using OpenGL ES and a few weeks ago I decided to re-boot the project with flat UI, vivid colours and UIDynamics to make things interesting.

This time the project took two solid weekends (and a few late nights), but I am pretty happy with how it turned out


If you are reading this and you live in Australia, make sure you check out goCatch next time you need to catch a taxi.

Permalink - Comments - Tags: Development,iPhone,App

Interactive Hundreds Charts

June 11, 2015, 12:16 pm

Four engaging math games to help children learn their multiplication tables.

Permalink - Comments - Tags: Development,iPhone,App

I love everything about Daredevil except the suit

May 2, 2015, 7:46 am

I think I would be ok with keeping the black mask for the entire show. Ok. Maybe not. But I wish I liked the suit.

All these were awesome

I don't know what it is, but this just doesn't do it for me. Is the pointy eyebrows, the weird glowing eyes?

I really want to love it (I love this show) but, sadly, I can't do it.

Then again they could do a lot worse and still be better than this S&M monstrosity.

I can't think of that movie without picturing ol Matt on his hands and knees carefully drawing the DD logo on the subway with a can of Zippo fuel so he can dramatically light it up later. What the hell was that about?

Yep ... that was a really bad movie.

Permalink - Comments - Tags: Misc

Royal Randwick

October 12, 2014, 11:16 pm

Just another places API data glitch that I needed to write down somewhere. The auto complete results for "Royal Randwick" has the suburb as "Randwick" which is all good:

The corresponding detail response has "Sydney" as the locality. Accurate but imprecise ;)

Permalink - Comments - Tags: Development