Google-S2 空间索引框架简介及部分API使用示例

举报
隔壁老汪 发表于 2022/06/23 22:59:06 2022/06/23
【摘要】 1.关于S2框架的一些知识 为避免翻译造成的部分名词的歧义和理解上的不便,我将Google S2的源代码和说明直接贴出来 (如果无法访问该网址请在我的GIT@OSC项目 Google-S2-demo下载文档。 Google Code S2在Google Code上的项目地址 Foursquare的S2的论文 S2Map算法的地图...

1.关于S2框架的一些知识

为避免翻译造成的部分名词的歧义和理解上的不便,我将Google S2的源代码和说明直接贴出来 (如果无法访问该网址请在我的GIT@OSC项目 Google-S2-demo下载文档。

Google Code S2在Google Code上的项目地址

Foursquare的S2的论文

S2Map算法的地图测试站点

2.使用S2计算空间地理位置

S2使用的是WGS84坐标(GPS导航坐标),如果你获得的是百度或者高德的地理坐标,请将其转换为GPS坐标,以防止计算的位置不准确。 2.1 计算地球上两个点之间的距离

double lat = 22.629164;
        double lgt =114.025514 ;
        S2LatLng s2LatLng = S2LatLng.fromDegrees(lat, lgt);
        S2Point s2Point = s2LatLng.toPoint();
        double earthDistance = s2LatLng.getEarthDistance(new S2LatLng(s2Point)); //单位为m
        System.out.println(earthDistance); //输出距离为0
        //s2LatLng.getDistance() //可以用于计算两点之间的弧度距离

2.2 计算地球上某个点是否在矩形区域内

String[] split = "114.025914,22.629364".split(",");
        String[] coord = "114.027745,22.623408".split(",");
        S2LatLngRect rect = new S2LatLngRect(S2LatLng.fromDegrees(Double.valueOf(split[1]),Double.valueOf(split[0])),
                S2LatLng.fromDegrees(Double.valueOf(coord[1]),Double.valueOf(coord[0])));
        // S2RegionCoverer coverer = new S2RegionCoverer();
        //设置cell
        //        coverer.setMinLevel(8);
        //        coverer.setMaxLevel(15);
       //        coverer.setMaxCells(500);
       //        S2CellUnion covering = coverer.getCovering(rect);

        double lat = 22.629164;
        double lgt =114.025514 ;
        S2LatLng s2LatLng = S2LatLng.fromDegrees(lat, lgt);
        boolean contains = rect.contains(s2LatLng.toPoint());
        System.out.println(contains);

2.3 计算点是否在在圆形区域内

double lng = 112.030500;
	 double lat = 27.970271;
         double capHeight = 600.5; //半径
	 S2LatLng s2LatLng= S2LatLng.fromDegrees(lat, lng);
	 S2Cap cap = S2Cap.fromAxisHeight(s2LatLng.toPoint(),capHeight);
	 
	  double lat2 = 22.629164;
	  double lgt2 =114.025514 ;
	  S2LatLng s2LatLng = S2LatLng.fromDegrees(lat2, lng2);
	  boolean contains = cap.contains(s2LatLng.toPoint());
	  System.out.println(contains);

2.3 计算点是否在在多边形内

String str = "114.025914,22.629364;114.027745,22.623408;114.028944,22.619712;114.030112,22.617669;114.033967,22.612966;114.042343,22.602816;114.046114,22.603997;114.048353,22.604289;114.049606,22.604455;114.050796,22.604898;114.051728,22.605412;114.053186,22.606647;114.054171,22.608369";
        double lat = 22.629164;
        double lgt =114.025514 ;
	 List<S2Point> vertices = Lists.newArrayList();
	for (String token : Splitter.on(';').split(str)) {
            int colon = token.indexOf(',');
            if (colon == -1) {
                throw new IllegalArgumentException(
                        "Illegal string:" + token + ". Should look like '114.139312,22.551337;114.120260,22.535537'");
            }
            double lngY = Double.parseDouble(token.substring(0, colon));
            double latX = Double.parseDouble(token.substring(colon + 1));
            vertices.add(S2LatLng.fromDegrees(latX, lngY).toPoint());
        }
	S2Loop s2Loop = new S2Loop(vertices);
	 S2Polygon polygon = new S2Polygon(s2Loop); //创建多边形
        S2Point s2Point = S2LatLng.fromDegrees(lat, lgt).toPoint();
       boolean contains = polygon.contains(s2Point);
	System.out.println(contains);

2.3 计算两个区域是否有交集

//计算一个正方形和多边形之间是否有交集
String str = "114.025914,22.629364;114.027745,22.623408;114.028944,22.619712;114.030112,22.617669;114.033967,22.612966;114.042343,22.602816;114.046114,22.603997;114.048353,22.604289;114.049606,22.604455;114.050796,22.604898;114.051728,22.605412;114.053186,22.606647;114.054171,22.608369";
        double lat = 22.629164;
        double lgt =114.025514 ;

        List<S2Point> vertices = Lists.newArrayList();

        for (String token : Splitter.on(';').split(str)) {
            int colon = token.indexOf(',');
            if (colon == -1) {
                throw new IllegalArgumentException(
                        "Illegal string:" + token + ". Should look like '114.139312,22.551337;114.120260,22.535537'");
            }
            double lngY = Double.parseDouble(token.substring(0, colon));
            double latX = Double.parseDouble(token.substring(colon + 1));
            vertices.add(S2LatLng.fromDegrees(latX, lngY).toPoint());
        }

        S2Loop s2Loop = new S2Loop(vertices);
        S2Polygon polygon = new S2Polygon(s2Loop);
        S2Point s2Point = S2LatLng.fromDegrees(lat, lgt).toPoint();
        boolean contains = polygon.contains(s2Point);
        System.out.println(contains);

        String[] split = "114.025914,22.629364".split(",");
        String[] coord = "114.027745,22.623408".split(",");
        S2LatLngRect rect = new S2LatLngRect(S2LatLng.fromDegrees(Double.valueOf(split[1]),Double.valueOf(split[0])),
                S2LatLng.fromDegrees(Double.valueOf(coord[1]),Double.valueOf(coord[0])));
        S2RegionCoverer coverer = new S2RegionCoverer();
        //设置cell
        coverer.setMinLevel(8);
        coverer.setMaxLevel(15);
        coverer.setMaxCells(500);
        S2CellUnion covering = coverer.getCovering(rect);
        for (S2CellId s2CellId : covering.cellIds()) {
            boolean b = polygon.mayIntersect(new S2Cell(s2CellId));
            if (b){
                System.out.println("两个区域之间含有交集.....");
            }
        }

3.关于S2框架的计算性能和精度

综合我目前在项目中的使用情况来看,S2框架的性能比我自己利用计算机图形学上的实现的地理空间位置计算算法更好,而且由于S2使用了索引机制并使用希伯来曲线来建立多层次的CellID,在计算的精确度上肯定是S2框架更高。个人推荐你使用S2解决空间位置计算位置,S2也有多种语言的实现,如PHP,Python等。

4.将Google-S2框架构的Maven项目依赖

因为Google官方并没有在Maven上发布Google-S2-Java的Maven依赖包,所以在项目中需要自己将S2项目的源码重构为一个Maven项目,然后上传到局域网的Maven私服中,方便项目使用。 我在GIT@OSC上已经将Google-S2项目重构为一个Maven项目,大家要使用的可以直接Clone下来。

文章来源: blog.csdn.net,作者:隔壁老瓦,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/wxb880114/article/details/91886186

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。