Source

clojure-geohash / src / geohash / core.clj

Full commit
Ning Sun 1a74fc2 








Ning Sun 266a0ba 
Ning Sun 1a74fc2 

Ning Sun 266a0ba 
Ning Sun 1a74fc2 

Ning Sun 266a0ba 
Ning Sun 1a74fc2 










Ning Sun 266a0ba 
Ning Sun 1a74fc2 




Ning Sun 266a0ba 

Ning Sun 1a74fc2 










Ning Sun 266a0ba 
Ning Sun 1a74fc2 




Ning Sun 266a0ba 

Ning Sun 1a74fc2 

Ning Sun 266a0ba 
Ning Sun 9724d54 






















Ning Sun 1a74fc2 
Ning Sun 9724d54 
Ning Sun 1a74fc2 
Ning Sun 9724d54 
Ning Sun 266a0ba 

Ning Sun 1a74fc2 
Ning Sun 9724d54 



Ning Sun fd1292b 




Ning Sun 9724d54 
Ning Sun 1a74fc2 


Ning Sun 9724d54 
Ning Sun 1a74fc2 
Ning Sun 9724d54 



Ning Sun 1a74fc2 
Ning Sun 96e40ef 


Ning Sun 266a0ba 
Ning Sun 96e40ef 
(ns geohash.core)

(def base32-codes "0123456789bcdefghjkmnpqrstuvwxyz")

(defn- base32-index [ch]
  (. base32-codes indexOf (str ch)))

(defstruct geocode-data
  :maxlon :minlon :maxlat :minlat
  :islon :bits :hashcode :hashstring)

(defn- do-encode
  [lat lon prec geocode-data]
  (if (= (count (:hashstring geocode-data)) prec)
    (:hashstring geocode-data)
    (if (true? (:islon geocode-data))
      (let [
            mid (/ (+ (:maxlon geocode-data) (:minlon geocode-data)) 2)
            maxlon (if (> lon mid) (:maxlon geocode-data) mid)
            minlon (if (> lon mid) mid (:minlon geocode-data))
            hashcode (if (> lon mid) 
                       (+ (bit-shift-left (:hashcode geocode-data) 1) 1) 
                       (+ (bit-shift-left (:hashcode geocode-data) 1) 0))
            bits (inc (:bits geocode-data))
            hashstring (if (= bits 5) 
                         (str (:hashstring geocode-data) (nth base32-codes hashcode)) 
                         (:hashstring geocode-data))]
        (recur lat lon prec
          (assoc geocode-data
            :maxlon maxlon
            :minlon minlon
            :hashcode (if (= bits 5) 0 hashcode)
            :bits (if (= bits 5) 0 bits)
            :hashstring hashstring
            :islon (not (:islon geocode-data)))))
      (let [
            mid (/ (+ (:maxlat geocode-data) (:minlat geocode-data)) 2)
            maxlat (if (> lat mid) (:maxlat geocode-data) mid)
            minlat (if (> lat mid) mid (:minlat geocode-data))
            hashcode (if (> lat mid) 
                       (+ (bit-shift-left (:hashcode geocode-data) 1) 1) 
                       (+ (bit-shift-left (:hashcode geocode-data) 1) 0))
            bits (inc (:bits geocode-data))
            hashstring (if (= bits 5) 
                         (str (:hashstring geocode-data) (nth base32-codes hashcode)) 
                         (:hashstring geocode-data))]
        (recur lat lon prec
          (assoc geocode-data
            :maxlat maxlat
            :minlat minlat
            :hashcode (if (= bits 5) 0 hashcode)
            :bits (if (= bits 5) 0 bits)
            :hashstring hashstring
            :islon (not (:islon geocode-data))))))))

(defn- do-decode-hashcode
  [bits hash-code geocode-data]
  (loop [bits 4 geocode-data geocode-data]
    (if (< bits 0) geocode-data
      (if (true? (:islon geocode-data))
        (let [
              bit (bit-and (bit-shift-right hash-code bits) 1)
              mid (/ (+ (:maxlon geocode-data) (:minlon geocode-data)) 2)
              minlon (if (= bit 1) mid (:minlon geocode-data))
              maxlon (if (= bit 1) (:maxlon geocode-data) mid)]
          (recur (dec bits)
            (assoc geocode-data
              :minlon minlon
              :maxlon maxlon
              :islon (not (:islon geocode-data)))))
        (let [
              bit (bit-and (bit-shift-right hash-code bits) 1)
              mid (/ (+ (:maxlat geocode-data) (:minlat geocode-data)) 2)
              minlat (if (= bit 1) mid (:minlat geocode-data))
              maxlat (if (= bit 1) (:maxlat geocode-data) mid)]
          (recur (dec bits)
            (assoc geocode-data
              :minlat minlat
              :maxlat maxlat
              :islon (not (:islon geocode-data)))))))))

(defn- do-decode-bbox [hash-codes geocode-data]
  (if (empty? hash-codes)
    geocode-data
    (let [local-geocode-data (do-decode-hashcode 5 (first hash-codes) geocode-data)]
      (recur (rest hash-codes) local-geocode-data))))

(defn decode-bbox [hashstring]
  (let [
        hashcodes (map base32-index hashstring)
        bbox (do-decode-bbox hashcodes (struct geocode-data 180.0 -180.0 90.0 -90.0 true nil nil nil))]
    (dissoc (hash-map geocode-data)
      :islon
      :bits
      :hashcode
      :hashstring)))

(defn decode [hashstring]
  (let [
        hashcodes (map base32-index hashstring)
        bbox (do-decode-bbox hashcodes (struct geocode-data 180.0 -180.0 90.0 -90.0 true nil nil nil))
        lat (/ (+ (:maxlat bbox) (:minlat bbox)) 2)
        lon (/ (+ (:maxlon bbox) (:minlon bbox)) 2)
        lat-err (/ (- (:maxlat bbox) (:minlat bbox)) 2)
        lon-err (/ (- (:maxlon bbox) (:minlon bbox)) 2)]
    {:lat lat :lon lon :lat-err lat-err :lon-err lon-err}))

(defn encode 
  ([lat lon] (encode lat lon 9))
  ([lat lon prec]
  (do-encode lat lon prec 
    (struct geocode-data 180 -180 90 -90 true 0 0 ""))))