package algo /** * Created by yanfenghua on 2017/09/26. */ object GeoHash { //经纬度单独编码长度 val numbits = 6 * 5 //32位编码对应字符 final val digits = Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z') //定义编码映射关系 val lookup = new java.util.HashMap[Character, Integer] //初始化编码映射内容 { var i = 0 for (c <- digits) lookup.put(c, { i += 1; i - 1 }) } //根据经纬度和范围,获取对应二进制 def getBits(lat: Double, floor: Double, ceiling: Double): java.util.BitSet = { val buffer = new java.util.BitSet(numbits) var i = 0 var floor_while = floor var celling_while = ceiling while (i < numbits) { val mid = (floor_while + celling_while) / 2 if (lat >= mid) { //记录的是值为1的index buffer.set(i) floor_while = mid } else { celling_while = mid } i += 1 } buffer } //将经纬度合并后的二进制进行指定的32位编码 def base32(i: Long): java.lang.String = { var j = i val buf = new Array[Char](65) var charPos = 64 val negative = j < 0 if (!negative) j = -j while (j <= -32) { buf({ charPos -= 1; charPos + 1 }) = digits((-(j % 32)).toInt) j = j / 32 } buf(charPos) = digits((-j).toInt) if (negative) buf({ charPos -= 1; charPos }) = '-' new java.lang.String(buf, charPos, 65 - charPos) } //对经纬度进行编码 def encode(lat_lon: (Double, Double)): java.lang.String = { val lat = lat_lon._1 val lon = lat_lon._2 val latbits = getBits(lat, -90, 90) val lonbits = getBits(lon, -180, 180) //将经度、维度二进制编码,合并起来,得到长度为60的二进制编码,再转成长度12位的geo码 val buffer = new StringBuilder var i = 0 while (i < numbits) { buffer.append(if (lonbits.get(i)) '1' else '0') buffer.append(if (latbits.get(i)) '1' else '0') i += 1 } base32(java.lang.Long.parseLong(buffer.toString, 2)) } //对编码后的字符串解码 def decode(geohash: String): Array[Double] = { val buffer = new StringBuilder() for (c <- geohash.toCharArray()) { var i = lookup.get(c) + 32 buffer.append(Integer.toString(i, 2).substring(1)) } val lonset = new java.util.BitSet() val latset = new java.util.BitSet() //偶数位,经度 var j = 0 var i_even = 0 while (i_even < numbits * 2) { var isSet = false if (i_even < buffer.length) isSet = buffer.charAt(i_even) == '1' lonset.set(({j += 1; j - 1}), isSet) i_even += 2 } //奇数位,纬度 j = 0 var i_odd = 1 while (i_odd < numbits * 2) { var isSet = false if (i_odd < buffer.length) isSet = buffer.charAt(i_odd) == '1' latset.set(({j += 1; j - 1}), isSet) i_odd += 2 } val lat = decode(latset, -90, 90) val lon = decode(lonset, -180, 180) Array[Double](lat, lon) } //根据二进制和范围解码 def decode(bs: java.util.BitSet, floor: Double, ceiling: Double): Double = { var mid = 0.0 var floor_foo = floor var ceiling_foo = ceiling for (i <- 0 until bs.length()) { mid = (floor_foo + ceiling_foo) / 2 if (bs.get(i)) floor_foo = mid else ceiling_foo = mid } mid } def main(args: Array[String]): Unit = { val s = encode(22.5346, 114.0554) println(s) val geo = decode(s) geo.foreach(println(_)) // Scala支持与Java的隐式转换 import scala.collection.JavaConversions._ //查看初始化生产的lookup for (key <- lookup.keySet()) { println("key : " + key+ " , value ; " + lookup.get(key)) } println(lookup) //将lookup的内容排序输出 val list = lookup.toList.sortWith(_._1 < _._1) println(list) } }输出情况:ws105qk9e3ym 22.534599993377924 114.05539993196726
GeoPartition算法Scala代码
最新推荐文章于 2021-01-20 14:05:32 发布