Geohash之范围搜索

概述

很多时候,我们都会遇到这样的需求:查找某个点周边多少距离的点。从本质来说,是一个缓冲区分析+空间查找,本文结合Geohash来实现类似的功能。

效果

范围搜索结果

说明:
  1. 红色的点和红色的圈是查找的中心点和距离(5km);
  2. 蓝色的点+粉色的点是通过geohash查找出来的点;
  3. 粉色的点是通过过滤后的点;

实现

本文实现是结合sqlite数据库实现的,实现的思路如下:

1. 数据的初始化

本示例所用的数据源于网络下载下来的shp数据,并做了解析入库,表结构如下:

CREATE TABLE "geocode_point"
(
  id NVARCHAR(50) PRIMARY KEY NOT NULL,
  poiname NVARCHAR(200),
  x NUMERIC,
  y NUMERIC,
  minzoom INTEGER(2),
  maxzoom INTEGER(2)
, geohash NVARCHAR(20) NULL)

数据展示

2. 根据geohash查找点

根据查找的距离范围,先获取geohash的位数,实现方法如下:

    /**
     * 获取距离有效位数
     * @param radius
     * @return
     */
    public int effectnum(double radius){
        int result = 0;
        if (radius <= 0) result = 0;
        else if (radius < 1) result = 10;
        else if (radius < 5) result = 9;
        else if (radius < 20) result = 8;
        else if (radius < 77) result = 7;
        else if (radius < 610) result = 6;
        else if (radius < 2400) result = 5;
        else if (radius < 20000) result = 4;
        else if (radius < 78000) result = 3;
        else if (radius < 630000) result = 2;
        else result = 0;
        return result;
    }

再查找前面的值相同的记录,实现代码如下:

int precision = geoHash.effectnum(dist);
String strGeohash = geoHash.encode(lat, lon, 0);
String filters = "where geohash like '"+strGeohash.substring(0, precision)+"%'";
List _list = geoDao.getDataByFilter(points.getTableName(), points.getTableFields(), filters, new Object[]{});

3. 计算满足条件的点

由于是经纬度的数据,所以在计算两点距离的时候进行了坐标转换,将经纬度转换为了Web墨卡托,此举是结合geotools实现的。

1)坐标转换
    public double[] lonlat2WebMactor(double lon, double lat){
        Point geom =new GeometryFactory().createPoint(new Coordinate(lon, lat));
        try{
            CoordinateReferenceSystem crsTarget = CRS.decode("EPSG:3857");
            // 投影转换
            MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, crsTarget);
            Point webPoint = (Point)JTS.transform(geom, transform);
            return new double[]{webPoint.getX(), webPoint.getY()};
        }
        catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
    }
2)计算距离
    public double distance(String geohash1, String geohash2){
        Map lonlat1 = decode(geohash1),
            lonlat2 = decode(geohash2);
        double lat1 = (Double) lonlat1.get("lat"),
                lon1 = (Double) lonlat1.get("lon");
        double lat2 = (Double) lonlat2.get("lat"),
                lon2 = (Double) lonlat2.get("lon");
        double[] webPoint1 = lonlat2WebMactor(lon1, lat1),
                webPoint2 = lonlat2WebMactor(lon2, lat2);
        return Math.sqrt(Math.pow(webPoint1[0]-webPoint2[0], 2d)+Math.pow(webPoint1[1]-webPoint2[1], 2d));
    };
3)筛选满足条件的点

将查询出来的结果做比较,筛选满足条件的点。

        for(int i=0;i<_list.size();i++){
            Map map = (Map)_list.get(i);
            String _geohash = map.get("geohash").toString();
            double _dist = geoHash.distance(strGeohash, _geohash);
            if(_dist<dist)list.add(map);
        }
        return list;

将2和3串起来,实现代码如下:

    public List searchByDist(double lon, double lat, double dist){
        List list = new ArrayList();
        int precision = geoHash.effectnum(dist);
        String strGeohash = geoHash.encode(lat, lon, 0);
        String filters = "where geohash like '"+strGeohash.substring(0, precision)+"%'";
        List _list = geoDao.getDataByFilter(points.getTableName(), points.getTableFields(), filters, new Object[]{});
        System.out.println(JSONArray.toJSONString(_list));
        for(int i=0;i<_list.size();i++){
            Map map = (Map)_list.get(i);
            String _geohash = map.get("geohash").toString();
            double _dist = geoHash.distance(strGeohash, _geohash);
            if(_dist<dist)list.add(map);
        }
        return list;
    }

技术博客
CSDN:http://blog.csdn.NET/gisshixisheng
博客园:http://www.cnblogs.com/lzugis/
在线教程
http://edu.csdn.Net/course/detail/799
Github
https://github.com/lzugis/
联系方式

类型内容
qq1004740957
公众号lzugis15
e-mailniujp08@qq.com
webgis群1004740957
Android群337469080
GIS数据可视化群458292378

LZUGIS

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛老师讲GIS

感谢老板支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值