兄弟篇:【搬砖笔记】 利用GeoHash为地理位置编码——理论篇。
一、前言
本篇介绍采用Java实现GeoHash算法,若有任何错误或建议,望不吝赐教,不胜感激。
二、 实现
完整代码见:GitHub
先罗列下实现的功能:
- 将经纬度转换为二进制编码,见
getBinary
函数。 - 将二进制编码转换为base32编码,见
getBase32
函数。 - (通用法)根据二进制编码、方向获取对应方向的邻块二进制编码,见
getNeighborWithDirection
函数。 - (通用法)根据二进制编码,获取邻近九宫格的二进制编码,见
getNeighbors
函数。 - (查表法)根据base32编码、方向获取对应方向的邻块base32编码,见
getNeighborsByTable
函数。 - (查表法)根据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");</