GeoPartition算法Scala代码

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值