Decoding Polylines from Google Maps Direction API with Clojure

Written by on 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" : "[email protected][email protected][email protected][email protected]@@[email protected]}@[email protected]?UDYJi@]^w@[email protected]@[email protected][email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]~@[email protected][email protected]@[email protected]@h@[email protected]@[email protected]@[email protected]@[email protected]][email protected]@[email protected]@[email protected]][email protected]@@eAT[L[[email protected]@[email protected]`XoAbEmB~GqAvDkDzIsFvNcAvCcFrRkBnHcE`Pq@[email protected]@[email protected][email protected]@[email protected][email protected]@[email protected]@[email protected][email protected]@[email protected][email protected][email protected]@[email protected]@[email protected]_BEiBUaEkAcA][email protected]@][email protected]@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]^Et@@[email protected]@[email protected]@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[[email protected][email protected]@[email protected]@[email protected]@uA_Di@[email protected]@[email protected]@[email protected][email protected]@[email protected][email protected]@[email protected]@[[email protected]@[email protected]@][email protected][email protected]@[email protected]@wDK}@@[g@[email protected]@gAk@[email protected]@[email protected]@[email protected]@[email protected][email protected]^iAx@[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]@[email protected][email protected][email protected]@eCVeDRiGF}FGiB[sBc@[email protected]@[email protected]@[email protected]@uByA}BaAwAMUw@[email protected]@[email protected]@[email protected]@[email protected]@[email protected][email protected][email protected]@[email protected]`CiHPcABYB[Dq@@][email protected]@[email protected]@[email protected]@~CuBbC_Bn@]d@[email protected]][email protected]@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 - Tags: Development,Clojure