Geohash求当前区域周围8个区域编码的一种思路

使用Geohash获取周围8个区域编码的方法
本文介绍了如何通过Geohash解决查询附近POI时出现的边界问题,提出在查询时同时考虑定位点及周围8个区域的GeoHash编码。详细解释了从经纬度二进制串加减1来获取相邻区域编码的思路,并提供了实现方法。

首先感谢GeoHash核心原理解析这篇文章让我明白了什么叫geohash

在这篇文章里,作者提出了几个使用geohash的注意点:

由于GeoHash是将区域划分为一个个规则矩形,并对每个矩形进行编码,这样在查询附近POI信息时会导致以下问题,比如红色的点是我们的位 置,绿色的两个点分别是附近的两个餐馆,但是在查询的时候会发现距离较远餐馆的GeoHash编码与我们一样(因为在同一个GeoHash区域块上),而 较近餐馆的GeoHash编码与我们不一致。这个问题往往产生在边界处。

解决的思路很简单,我们查询时,除了使用定位点的GeoHash编码进行匹配外,还使用周围8个区域的GeoHash编码,这样可以避免这个问题。

那么如何得到周围8个区域的geohash编码呢,作者没有提供更明确的思路,在网上也搜索不到相关的解决办法,所以在这里提大家提供我的思路。

看到这里,我假设各位已经清楚如何对经纬度进行geohash编码。
在对经度进行二分逼近时,落在左边区间为0,右边为1:
第一次划分:这里写图片描述
第二次划分:这里写图片描述
第三次划分:这里写图片描述

可以看出每一块区域的编码,从左往右依次对应了十进制的0~(2^n)-1,同样的,对纬度逼近的过程中,每一块区域从下往上同样依次对应0~(2^n)-1。
因此,很容易的就能求出周围区域的geohash值:
1. 将当前区域的geohash编码解码成经纬度对应的二进制串
2. 将二进制串+1或者-1就能得到左右经度(或上下纬度)区域对应的二进制串(注意边界)
3. 得到的经纬度二进制串两两组合再进行geohash的编码,得到的就是周围区域的编码了。
代码如下:

/**
     * 求与当前geohash相邻的8个格子的geohash值。
     * @param geohash
     * @return string数组,周围格子的geohash值
     * @throws LengthOutOfRangException
     *             geohash长度超出范围(<=12)
     */
    public String[] expand(String geohash) throws LengthOutOfRangException {
        if (geohash.length() > 12)
            throw new LengthOutOfRangException("The length of geohash is out of range");
        String bCoordinate = decodeToBinary(geohash);//当前geohash值对应的二进制串

        StringBuilder bLat = new StringBuilder();
        StringBuilder bLon = new StringBuilder();

        for (int i = 0; i < bCoordinate.length(); i++) {
            if ((i % 2) == 0) {
                bLon.append(bCoordinate.charAt(i));
            } else {
                bLat.append(bCoordinate.charAt(i));
            }
        }
        String lat = bLat.toString();
        String lon = bLon.toString();

        String downLat = calculate(lat, -1);
        String upLat = calculate(lat, 1);
        String leftLon = calculate(lon, -1);
        String rightLon = calculate(lon, 1);

        return new String[] { encode(upLat,leftLon), encode(upLat,lon), encode(upLat,rightLon), encode(lat,leftLon),
                geohash, encode(lat,rightLon), encode(downLat,leftLon), encode(downLat,lon),
                encode(downLat,rightLon) };
    }

    /**
     * 计算当前格子左右(上下)格子的经(纬)度值二进制串
     * 
     * @param coordinate
     *            当前格子的经/纬度值
     * @param i
     *            偏移量
     * @return
     */
    private String calculate(String coordinate, int i) {
        int length = coordinate.length();
        String result = Integer.toBinaryString((Integer.valueOf(coordinate, 2) + i) + (1 << length)).substring(1);
        if (result.length() != length) {
            return null;
        } else {
            return result;
        }
    }
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值