Skip to content

Instantly share code, notes, and snippets.

@yuroyoro
Created January 13, 2010 14:02
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yuroyoro/276207 to your computer and use it in GitHub Desktop.
Save yuroyoro/276207 to your computer and use it in GitHub Desktop.
object GeoHash{
val base32 = "0123456789bcdefghjkmnpqrstuvwxyz"
def encode( longtitude:Double, latitude:Double, range:Double) = {
def asBit( d:Double,max:Double,min:Double ) : List[Boolean] = {
val mid = ( max + min ) / 2
var res = ( d >= mid )
val (m,n) = if( res ) (max,mid) else (mid,min)
if( Math.abs( m - n ) <= range )
res :: Nil
else
res :: asBit( d ,m ,n )
}
def asBase32( xs:List[Boolean] ):String = {
base32( (0.0 /: xs.reverse.zipWithIndex){
case( n,(b,i) ) => if( b ) n + Math.pow( 2, i ) else n
} toInt
).toString
}
def encodeBits( xs:List[Boolean] ):String = xs match{
case Nil => ""
case _ =>
val (h,t) = xs.splitAt(5)
asBase32(h) + encodeBits( t )
}
val bits = asBit(longtitude , 180,-180 ).
zipAll( asBit( latitude, 90, -90 ), false, false ).
flatMap{ case (a,b) => a::b::Nil }
encodeBits( bits ).reverse.dropWhile( '0' == ).reverse.mkString
}
def decode( geohash:String ):((Double,Double),(Double,Double)) = {
def toBitList( s:String ) = s.flatMap{
c => ("00000" + base32.indexOf(c).toBinaryString ).
reverse.take(5).reverse.map('1' == ) } toList
def split( l:List[Boolean] ):(List[Boolean],List[Boolean]) ={
l match{
case Nil => (Nil,Nil)
case x::Nil => ( x::Nil,Nil)
case x::y::zs => val (xs,ys) =split( zs );( x::xs,y::ys)
}
}
def dehash( xs:List[Boolean], min:Double, max:Double ):(Double,Double) = {
((min,max) /: xs ){
case ((min,max) ,b) =>
if( b )( (min + max )/2 , max )
else ( min,(min + max )/ 2 )
}
}
val ( xs ,ys ) = split( toBitList( geohash ) )
( dehash( xs, -180,180 ) , dehash( ys ,-90,90) )
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment