1.什么是RTree

待补充

2.RTree java依赖

rtree的java开源版本在GitHub上:https://github.com/davidmoten/rtree

上面有详细的使用说明

最新版本的maven依赖可在中央仓库查到:https://mvnrepository.com/artifact/com.github.davidmoten/rtree

这里我们使用0.8.7版本

  1. <!-- https://mvnrepository.com/artifact/com.github.davidmoten/rtree -->
  2. <dependency>
  3. <groupId>com.github.davidmoten</groupId>
  4. <artifactId>rtree</artifactId>
  5. <version>0.8.7</version>
  6. </dependency>

3.使用

3.1创建R树

创建R树

  1. //创建时,可以指定最小、最大孩子结点数,splitter,selector
  2. RTree<String, Geometry> tree = RTree.minChildren(3).maxChildren(6).create();

创建R*树

R*树是R树的变种,是在节点分裂方法上做了改进的R树,这点后续再写篇博客详细介绍

  1. RTree<String, Geometry> tree = RTree.star().maxChildren(6).create();

这样,第一步创建R树操作就完成了,是不是很简单!!!

3.2 往R树插入数据

可插入4种空间数据:点、线、圆、矩形

  • Geometries.Rectangle
  • Geometries.circle
  • Geometries.point
  • Geometries.line

为什么没有面数据呢?

  • 面其实也是多个线的组合,只需要将多边形的边依次插入R树就行
  1. //插入点数据
  2. tree = tree.add("testPoint", Geometries.point(116.0D, 32.0D));

3.3 删除R树里的数据

删除的时候需要匹配名称和地理信息

  1. //删除点数据
  2. tree = tree.delete("testPoint", Geometries.point(116.0D,32.0D));

3.4 搜索

R树对空间信息的查找平均时间复杂度是O(logN),最坏情况下是O(N)

搜索方法返回的结果需要Observable泛型

  1. Observable<Entry<String, Point>> entries = tree.search(Geometries.rectangle(8, 15, 30, 35));

或者返回Iterable类型

  1. Iterable<Entry<String, Point>> result = tree.search(Geometries.point(116.11D, 31.11D))
  2. .toBlocking().toIterable();

4. 应用:判断点是否在多边形内

说明:R树是用外接矩形判断点是否在矩形框内,只能用作粗筛,因此粗筛了一遍后,还需要用射线法做精确判断。有关射线法判断点在多边形内的方法可自行搜索。

假设业务场景是:我有很多个多边形数据,如商场AOI数据。现在需要通过用户的经纬度坐标判断用户在哪个商场里,从而按地理位置精准给用户推荐周边店铺营销信息

这里的输入就是用户经纬度,输出是用户所在的商场。

设计

上文说过,R树要存多边形只能存它的边数据。这样操作之后,一个多边形就是一棵R树了,但是搜索是在多个多边形里找到能命中的,因此还需要再加一层R树,即用每个多边形的外接矩形构建父R树。详细设计如下:

构建R树

具体逻辑如下:

  1. //北京市东城区和西城区的边界,这里只展示部分数据,非完全边界数据
  2. private String dongcheng = "MULTIPOLYGON(((116.38059 39.871148,116.399097 39.872205,116.397612 39.898675,1116.38059 39.871148)))";
  3. private String xicheng = "MULTIPOLYGON(((116.387658 39.96093,116.38678 39.957014,116.393346 39.957355,116.387658 39.96093)))";
  4. private RTree<String, Rectangle> secondTree = RTree.minChildren(3).maxChildren(6).create();
  5. public void build() {
  6. List<CityDTO> sourceData = buildCityDTOs();
  7. //1.对每个多边形,存入所有边构建一级R树
  8. for (CityDTO sourceDatum : sourceData) {
  9. RTree<String, Line> tree = RTree.minChildren(3).maxChildren(6).create();
  10. List<List<Double>> polygon = GeoHelper.transfer2List(sourceDatum.getShape());
  11. for (int i = 0; i < polygon.size(); i++) {
  12. List<Double> nextPoints = polygon.get((i + 1) % polygon.size());
  13. List<Double> points = polygon.get(i);
  14. Double lng1 = points.get(0);
  15. Double lat1 = points.get(1);
  16. Double lng2 = nextPoints.get(0);
  17. Double lat2 = nextPoints.get(1);
  18. tree = tree.add(String.valueOf(i), Geometries.line(lng1, lat1, lng2, lat2));
  19. }
  20. //2. 将每个多边形的外接矩形构造为二级R树
  21. secondTree = secondTree.add(sourceDatum.getName(), tree.mbr().get());
  22. }
  23. }

搜索

  1. /**
  2. * 输入点坐标,查询命中的多边形name
  3. * @param lng
  4. * @param lat
  5. * @return
  6. */
  7. public String search(Double lng, Double lat) {
  8. Point point = Geometries.point(lng, lat);
  9. //r树粗筛一遍
  10. Iterator<Entry<String, Rectangle>> iterator = tree.search(point).toBlocking().toIterable().iterator();
  11. //射线法对粗筛的多边形精确计算
  12. while (iterator.hasNext()) {
  13. Entry<String, Rectangle> entry = iterator.next();
  14. String name = entry.value();
  15. //获取多边形wkt
  16. String wkt = localShapeCache.get(name);
  17. //射线法判断
  18. PointDTO p = new PointDTO();
  19. p.setLng(lng);
  20. p.setLat(lat);
  21. if (isInPolygon(p, GeoHelper.transfer2List(wkt))) {
  22. return name;
  23. }
  24. }
  25. return null;
  26. }

射线法判断点在多边形内

  1. /**
  2. * 射线法判断点是否在多边形内
  3. * @param pointDTO
  4. * @param polygon
  5. * @return
  6. */
  7. private boolean isInPolygon(PointDTO pointDTO, List<List<Double>> polygon) {
  8. int nCross = 0;
  9. for (int i = 0; i < polygon.size(); i++) {
  10. List<Double> p1 = polygon.get(i);
  11. List<Double> p2 = polygon.get((i + 1) % polygon.size());
  12. Double lng1 = p1.get(0);
  13. Double lat1 = p1.get(1);
  14. Double lng2 = p2.get(0);
  15. Double lat2 = p2.get(1);
  16. //p1p2 与 y = p0.y平行
  17. if (lng1.equals(lng2)) {
  18. continue;
  19. }
  20. //交点在p1p2的延长线上
  21. if (pointDTO.getLng() < Math.min(lng1, lng2)) {
  22. continue;
  23. }
  24. //交点在p1p2的延长线上
  25. if (pointDTO.getLng() >= Math.max(lng1, lng2)) {
  26. continue;
  27. }
  28. // 求交点的X坐标
  29. double x = (pointDTO.getLng() - lng1) * (lat2 - lat1) / (lng2 - lng1) + lat1;
  30. if (x > pointDTO.getLat()) {
  31. //只统计单边
  32. nCross++;
  33. }
  34. }
  35. //单边交点为奇数,点在多边形内
  36. return (nCross % 2 == 1);
  37. }

生成多边形的外接矩形

  1. /**
  2. * 获取多边形的外接矩形
  3. * @param wkt
  4. * @return
  5. */
  6. public Rectangle buildRectFromWkt(String wkt) {
  7. double minLng = 180.00;
  8. double minLat = 90;
  9. double maxLng = -180.00;
  10. double maxLat = -90.00;
  11. //wkt格式数据转为点 list
  12. List<List<Double>> polygon = GeoHelper.transfer2List(wkt);
  13. for (List<Double> points : polygon) {
  14. Double lng = points.get(0);
  15. Double lat = points.get(1);
  16. if (lng < minLng) {
  17. minLng = lng;
  18. }
  19. if (lng > maxLng) {
  20. maxLng = lng;
  21. }
  22. if (lat < minLat) {
  23. minLat = lat;
  24. }
  25. if (lat > maxLat) {
  26. maxLat = lat;
  27. }
  28. }
  29. return Geometries.rectangle(minLng, minLat, maxLng, maxLat);
  30. }

R树判断点在多边形内-Java版本的更多相关文章

  1. 判断点在多边形内算法的C++实现

    目录 1. 算法思路 2. 具体实现 3. 改进空间 1. 算法思路 判断平面内点是否在多边形内有多种算法,其中射线法是其中比较好理解的一种,而且能够支持凹多边形的情况.该算法的思路很简单,就是从目标 ...

  2. hdu 1756:Cupid's Arrow(计算几何,判断点在多边形内)

    Cupid's Arrow Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tot ...

  3. POJ 2318 TOYS | 二分+判断点在多边形内

    题意: 给一个矩形的区域(左上角为(x1,y1) 右下角为(x2,y2)),给出n对(u,v)表示(u,y1) 和 (v,y2)构成线段将矩形切割 这样构成了n+1个多边形,再给出m个点,问每个多边形 ...

  4. zoj 1081 判断点在多边形内

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=81Points Within Time Limit: 2 Second ...

  5. php之判断点在多边形内的api

    1.判断点在多边形内的数学思想:以那个点为顶点,作任意单向射线,如果它与多边形交点个数为奇数个,那么那个点在多边形内,相关公式: <?php class AreaApi{ //$area是一个多 ...

  6. ZOJ 1081 Points Within | 判断点在多边形内

    题目: 给个n个点的多边形,n个点按顺序给出,给个点m,判断m在不在多边形内部 题解: 网上有两种方法,这里写一种:射线法 大体的思想是:以这个点为端点,做一条平行与x轴的射线(代码中射线指向x轴正方 ...

  7. hdu 1756 判断点在多边形内 *

    模板题 #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> ...

  8. A Round Peg in a Ground Hole - POJ 1584 (判断凸多边形&判断点在多边形内&判断圆在多边形内)

    题目大意:首先给一个圆的半径和圆心,然后给一个多边形的所有点(多边形按照顺时针或者逆时针给的),求,这个多边形是否是凸多边形,如果是凸多边形在判断这个圆是否在这个凸多边形内.   分析:判断凸多边形可 ...

  9. matlab inpolygon 判断点在多边形内

    如何判断一个点在多边形内部? xv= [0 3 3 0 0]; %x坐标 yv= [0 0 3 3 0];%y坐标 x=1.5; y=1.5; in=inpolygon(x,y,xv,yv) plot ...

随机推荐

  1. Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?

    启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解: @SpringBootConfiguration:组合了 ...

  2. 你如何确保 main()方法所在的线程是 Java 程序最后结束 的线程?

    我们可以使用 Thread 类的 join()方法来确保所有程序创建的线程在 main()方法退出前结束.

  3. su 和 sudo的区别

    su是一个命令,可切换其他用户进行操作:而 '-' 号则是代表是否完全切换指定的用户环境信息 sudo是一个服务,可通过/etc/sudoers进行配置文件,让被限制的用户只能执行被授予的命令操作.

  4. Qt的.pro文件格式解析

    Qt的.pro文件格式解析 在Qt中用qmake生成makefile文件,它是由.pro文件生成而来的,.pro文件的具体格式语法如下: 1.注释 .pro文件中注释采用#号,从"#&quo ...

  5. 关于css布局、居中的问题以及一些小技巧

    CSS的两种经典布局 左右布局 一栏定宽,一栏自适应 <!-- html --> <div class="left">定宽</div> < ...

  6. 从CSS盒子模型说起

    前言 总括: 对于盒子模型,BFC,IFC和外边距合并等概念和问题的总结 原文地址:从CSS盒子模型说起 知乎专栏:前端进击者 博主博客地址:Damonare的个人博客 为学之道,莫先于穷理:穷理之要 ...

  7. javascript入门教程(二):变量

    大家好,我从今天开始就会正式讲javascript的语法方面.变量 js中的变量一般使用var来声明(es6的let不在本教程讨论范围内),可以用来定义任何种类的变量,如果只对变量进行了定义而没有赋值 ...

  8. PAT1018 锤子剪刀布

    大家应该都会玩"锤子剪刀布"的游戏:两人同时给出手势,胜负规则如图所示: 现给出两人的交锋记录,请统计双方的胜.平.负次数,并且给出双方分别出什么手势的胜算最大. 输入格式: 输入 ...

  9. ssm 框架实现增删改查CRUD操作(Spring + SpringMVC + Mybatis 实现增删改查)

    ssm 框架实现增删改查 SpringBoot 项目整合 一.项目准备 1.1 ssm 框架环境搭建 1.2 项目结构图如下 1.3 数据表结构图如下 1.4 运行结果 二.项目实现 1. Emplo ...

  10. ssm项目框架搭建(增删改查案例实现)——(SpringMVC+Spring+mybatis项目整合)

    Spring 常用注解 内容 一.基本概念 1. Spring 2. SpringMVC 3. MyBatis 二.开发环境搭建 1. 创建 maven 项目 2. SSM整合 2.1 项目结构图 2 ...