Geohash
- 平成22年1月14日(木) 22時26分25秒
- 区分
- 疎外感
- 報告者:
- chiba
こんにちは、chibaです。 昨晩は、弊社技師同僚間のTwitterで、Geohashの話題が盛り上っておりました。 話に混ざれずに疎外感を感じつつ就寝しようとしたのですが、ふと、会話中で示されていたGeohashの説明のページを眺めたところ、仕組みが分かるようで、分からないような、微妙にもどかしい感じだったので、だらだらと説明のとおりに上から順にコードを書いてみることにしました。
(defpackage :geohash
(:use :cl)
(:import-from :shibuya.lisp
:$ :$*))
(in-package :geohash)
(defun tr (from to string)
(map 'string
(lambda (c)
(or (some (lambda (x y)
(and (char-equal x c) y))
from to)
(char-upcase c)))
string))
(defun 5bits (string)
(map 'list
($ format nil "~5,'0,B"
$ read-from-string
$ format nil "#32R~A"
$ tr "0123456789BCDEFGHJKMNPQRSTUVWXYZ"
"0123456789ABCDEFGHKJKLMNOPQRSTUV"
$ string $)
string))
(defun longitude-latitude (strings)
(let ((bit-c-list ($* concatenate 'list strings)))
(loop :for c :in bit-c-list
:for i :from (if (char= #\0 (car bit-c-list)) 0 1)
:if (evenp i) :collect c :into even
:else :collect c :into odd
:finally (return
(list :longitude
(coerce even 'string)
:latitude
(coerce odd 'string))))))
(defun bitlist (string)
(map 'list ($ parse-integer $ string $)
string))
(defun decode (bits min mid max)
(if (endp bits)
mid
($* decode
(cdr bits)
(if (zerop (car bits))
(list min (/ (+ mid min) 2) mid)
(list mid (/ (+ mid max) 2) max)))))
(defun decode-geohash (string)
(let* ((u ($ longitude-latitude $ 5bits string))
(lon (getf u :longitude))
(lat (getf u :latitude)))
(list
:longitude
($ float $ decode (bitlist lon) -90 0 90)
:latitude
($ float $ decode (bitlist lat) -180 0 180))))
(decode-geohash "u4pruydqqvj")
;⇒ (:LONGITUDE 57.64911 :LATITUDE 10.407439)