【搬砖笔记】 利用GeoHash为地理位置编码——实现篇

兄弟篇:【搬砖笔记】 利用GeoHash为地理位置编码——理论篇

一、前言

本篇介绍采用Java实现GeoHash算法,若有任何错误或建议,望不吝赐教,不胜感激。

二、 实现

完整代码见:GitHub

先罗列下实现的功能:

  1. 将经纬度转换为二进制编码,见 getBinary函数。
  2. 将二进制编码转换为base32编码,见getBase32函数。
  3. (通用法)根据二进制编码、方向获取对应方向的邻块二进制编码,见getNeighborWithDirection函数。
  4. (通用法)根据二进制编码,获取邻近九宫格的二进制编码,见getNeighbors函数。
  5. (查表法)根据base32编码、方向获取对应方向的邻块base32编码,见getNeighborsByTable函数。
  6. (查表法)根据base32编码,获取邻近九宫格的base32编码,见getNeighborsByTable函数。

实现代码如下:

import java.util.HashMap;
import java.util.Map;

public class GeoHash {
   

    /**
     * 经度最小值
     */
    private static final double MIN_LONGTITUDE = -180.0;

    /**
     * 经度最大值
     */
    private static final double MAX_LONGTITUDE = 180.0;

    /**
     * 纬度最小值
     */
    private static final double MIN_LATITUDE = -90.0;

    /**
     * 纬度最大值
     */
    private static final double MAX_LATITUDE = 90.0;

    /**
     * 二进制表达最长为64位
     */
    private static final Integer MAX_BINARY_BITS = 64;

    /**
     * base32编码最长为13位,因为 5*13 = 65 > 64
     */
    private static final Integer MAX_BASE32_LENGTH = 13;

    /**
     * 每五个bit转换为base32编码
     */
    private static final int ENCODE_EVERY_BITS = 5;

    /**
     * base32 编码表
     */
    private static final char[] BASE32_LOOKUP = {
   '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'};

    /**
     * base32 反编码对照表
     */
    private final static Map<Character, Integer> BASE32_DECODE_LOOKUP = new HashMap<>();

    /**
     * 编码 0 填充对照表
     */
    private static final String[] PADDING_LOOKUP = {
   "", "0", "00", "000", "0000"};

    /**
     * 方向枚举
     */
    private enum Direction {
   
        Top,
        Right,
        Bottom,
        Left;
    }

    /**
     * 奇数查表
     */
    private static Map<Direction, String> ODD_LOOKUP = new HashMap<>(4);

    /**
     * 偶数查表
     */
    private static Map<Direction, String> EVEN_LOOKUP = new HashMap<>(4);

    /**
     * 奇数查表边界
     */
    private static Map<Direction, String> ODD_BORDERS = new HashMap<>(4);

    /**
     * 偶数查表边界
     */
    private static Map<Direction, String> EVEN_BORDERS = new HashMap<>(4);

    /**
     * 64bit中第一位的标记
     */
    private static final long FIRST_BIT_FLAGGED = 0x8000000000000000L;

    /**
     * 静态块
     */
    static {
   
        for (int i = 0; i < BASE32_LOOKUP.length; i++) {
   
            BASE32_DECODE_LOOKUP.put(BASE32_LOOKUP[i], i);
        }
        ODD_LOOKUP.put(Direction.Top, "238967debc01fg45kmstqrwxuvhjyznp");
        ODD_LOOKUP.put(Direction.Right, "14365h7k9dcfesgujnmqp0r2twvyx8zb");
        ODD_LOOKUP.put(Direction.Bottom, "bc01fg45238967deuvhjyznpkmstqrwx");
        ODD_LOOKUP.put(Direction.Left, "p0r21436x8zb9dcf5h7kjnmqesgutwvy");
        EVEN_LOOKUP.put(Direction.Top, "14365h7k9dcfesgujnmqp0r2twvyx8zb");
        EVEN_LOOKUP.put(Direction.Right, "238967debc01fg45kmstqrwxuvhjyznp");
        EVEN_LOOKUP.put(Direction.Bottom, "p0r21436x8zb9dcf5h7kjnmqesgutwvy");</
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
geohash简介: geohash是一种地址编码,它能把二维的经纬度编码成一维的字符串。geohash有以下几个特点: 首先,geohash用一个字符串表示经度和纬度两个坐标。某些情况下无法在两列上同时应用索引 (例如MySQL 4之前的版本,Google App Engine的数据层等),利用geohash,只需在一列上应用索引即可。 其次,geohash表示的并不是一个点,而是一个矩形区域。比如编码wx4g0ec19,它表示的是一个矩形区域。 使用者可以发布地址编码,既能表明自己位于北海公园附近,又不至于暴露自己的精确坐标,有助于隐私保护。 第三,编码的前缀可以表示更大的区域。例如wx4g0ec1,它的前缀wx4g0e表示包含编码wx4g0ec1在内的更大范围。 这个特性可以用于附近地点搜索。首先根据用户当前坐标计算geohash(例如wx4g0ec1)然后取其前缀进行查询 (SELECT * FROM place WHERE geohash LIKE 'wx4g0e%'),即可查询附近的所有地点。Geohash比直接用经纬度的高效很多。用途: 移动互联网,lbs可以说是一个基础应用,geohash对于解决附近地点搜索提供了一个有效的解决方案。扩展: 这个php扩展,提供了三个函数:/**     *  $latitude    //纬度     *  $longitude   //经度     *  $precision   //精密度, 默认是12     *  返回 $precision 长度的 string     */    geohash_encode($latitude, $longitude, $precision=12);      /**     *  $hash    //geohash_encode后的值     *  返回 array // Array     *                    (     *                        [latitude] => 39.416916975752     *                        [longitude] => 100.92223992571     *                        [north] => 39.416917059571     *                        [east] => 100.92224009335     *                        [south] => 100.92223992571     *                        [west] => 100.92223975807     *                    )     */    geohash_decode($hash);    /**     *  $hash    //geohash_encode后的值     *  返回 在$hash 8个 (东南西北各二个)附近的hash值     */    geohash_neighbors($hash); 标签:geohash

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值