ch.hsr.geohash 是开源项目,可以让你在java项目中方便的进行经纬度的geohash相关计算,如果您对geohash比较陌生,可以看之前的geohash的简明介绍文章。
本文涉及到点
- ch.hsr.geohash包涉及模块
- ch.hsr.geohash包涉及的一些算法
- ch.hsr.geohash包涉及的应用场景
模块
geohash包涉及类很少,基本就是围绕生成、解析geohash的工作展开
:.
│ BoundingBox.java # 边界盒型类
│ GeoHash.java # geohash的主要计算操作类
│ WGS84Point.java # WGS84的坐标点类
│
├─queries
│ GeoHashBoundingBoxQuery.java # geohash盒型查询
│ GeoHashCircleQuery.java # geohash循环查询
│ GeoHashQuery.java # geohash查询
│
└─util
BoundingBoxGeoHashIterator.java #盒型geohash迭代器
BoundingBoxSampler.java #
GeoHashSizeTable.java # geohash的尺寸表
LongUtil.java #
TwoGeoHashBoundingBox.java # 使用两个geohash值构建一个外接盒型
VincentyGeodesy.java # VicentyGeo绘制算法
BoundingBox.java
边界盒型类,我自己这样命名的,该类主要构造方法有三个,但功能都是近似的,使用坐标构建出一个矩形(类似于geohash,但是表达方式不一样,geohash是利用矩形中心点坐标来描述矩形、BoundingBox使用“左下”和“右上”两个点来描述矩形)
# 构造方法
public BoundingBox(WGS84Point p1, WGS84Point p2) {
this(p1.getLatitude(), p2.getLatitude(), p1.getLongitude(), p2.getLongitude());
}
public BoundingBox(double y1, double y2, double x1, double x2) {
this.minLon = Math.min(x1, x2);
this.maxLon = Math.max(x1, x2);
this.minLat = Math.min(y1, y2);
this.maxLat = Math.max(y1, y2);
}
public BoundingBox(BoundingBox that) {
this(that.minLat, that.maxLat, that.minLon, that.maxLon);
}
该类具有一些工具方法,比如
- 判断一个点是否在该矩形内
- 判断两个矩形是否有交集
- 获取矩形的中心点
- 把一个矩形填充到另外矩形中
GeoHash.java
geohash的核心类,使用者可以通过该类进行经纬度与geohash的转换
生成geohash对象有三种形式(静态工厂方法)
- double类型经纬度值+字符串精度级别
- double类型经纬度值+bit位数的精度级别
- 二进制字符串
- geohash字符串
- 用long表示的二进制数+标识位
# double类型经纬度值+字符串精度级别
public static GeoHash withCharacterPrecision(double latitude, double longitude, int numberOfCharacters)
# double类型经纬度值+bit位数的精度级别
public static GeoHash withBitPrecision(double latitude, double longitude, int numberOfBits)
# 二进制字符串
public static GeoHash fromBinaryString(String binaryString)
# geohash字符串
public static GeoHash fromGeohashString(String geohash)
# 用long表示的二进制数+标识位
public static GeoHash fromLongValue(long hashVal, int significantBits)
为什么geohash的精度要区分使用字符串标识和二进制标识呢?这个可以看geohash的简明介绍里面的关于geohash值的计算。
在静态工厂方法中,我们也可以看到,关于精度,geohash字符形式的精度只有12位,二进制的精度是60位。因为5个二进制位对应一个Base32中字符(geohash特殊的Base32映射字面量,非标准Base32)
WGS84Point.java
涉及算法
列举其中比较关键或者实现巧妙的方法
- 把二进数根据奇偶位分解(geohash逆计算中二进制反解经纬度)
// 方法标记:ch.hsr.geohash.GeoHash#extractEverySecondBit(long copyOfBits, int numberOfBits)
public static final long FIRST_BIT_FLAGGED = 0x8000000000000000L;// 如常量名,BIT的首位校验标识,用于判断二进制数首位
private long extractEverySecondBit(long copyOfBits, int numberOfBits) {
long value = 0; // 奇数位或偶数位的保存值
for (int i = 0; i < numberOfBits; i++) {// 遍历geohash二进制数值
if ((copyOfBits & FIRST_BIT_FLAGGED) == FIRST_BIT_FLAGGED) {
value |= 0x1;//如果解析当前geohash二进制首位为1,则value当前二进制位置为1
}
value <<= 1;// 保存值左移1位
copyOfBits <<= 2;// geohash值左移两位、首位变为下一个偶数位
}
value >>>= 1;// 结束时,无符号右移一位,取消最后的保存值左移一位(取消最后value<<=1)
return value;
}
应用场景
- 遍历一个区域内的指定精度的经纬度
- 二维地址的降维与变形,方便做地址与经纬度的映射关系
网友评论