移动端应用开发过程中经常需要计算地理空间关系,例如:快递员/外卖员是否已抵达小区附近,办公打卡签到时是否在公司周边,共享单车是否停放在指定区域或禁停区等等。

前面我们介绍过如何使用MySQL进行地理坐标计算,不过这个方案存在几个局限性:

  1. 所有地理数据必须入库存储,有时候我们可能只是单纯想内存计算一下;
  2. MySQL不支持曲线计算,只能通过线段拟近,存在一定误差;
  3. 对于航空空域等计算场景,当地理坐标跨越了换日线时,无法直接用几何图形表示地理关系。

上面第三点是作者在做实际项目时遇到的问题,因此在这里介绍另一种计算地理空间关系的方案,以及个人在实践过程中踩过的一些坑。

一、地理坐标系统

地理空间计算一般有两种坐标系统:地理坐标系以及投影坐标系。

地理坐标系就是按球面坐标计算地理关系,坐标单位是经纬度,通过经纬线将参考椭球划分格网以度量其表面特定位置。当我们以东/西经和南/北纬指代位置时,我们就在使用地理坐标系。

投影坐标系是平面坐标系,参考平面是水平面,坐标单位是米、千米等。投影坐标系的基础是地理坐标系,它定义了如何将球面上的一个点映射到平面坐标上。根据投影方法的不同,各类投影坐标的平面图形也不尽相同,如下图所示:

  1. 圆锥投影
  2. 圆柱投影
  3. 平面投影
  4. 极方位投影

因此不管是地理坐标系还是投影坐标系,都可以通过一定的转换方式将其转化为平面坐标计算。

二、场景分解

地理空间计算主要有几种常见类型:相交、包含、最短距离等等,这里为简化计算,选取点是否被平面包含这一例子进行分析。

简单地理空间计算

计算点是否被特定地理平面所包含,一个简单的方法是利用图形API库,例如Java里的2D API。在内存中构建对应图形对象,使用关系函数即可求得结果。不过这里的前提是需要将地理数据转换为图形对象,对于数据量较小的场景可以快速处理,例如上面办公打卡签到,只需要对公司大楼图形坐标进行转换即可。

复杂计算场景

考虑另一个场景,飞机航行过程中,如何判断当前处于哪些空域范围内。国际上将各个地理空间范围规划为不同的空域,并赋予不同的管理级别,例如我国民航可用空域面积319.53万平方公里,占比32%,其余为军用或受控制空域。实时掌握飞机当前所处空域,能够帮助规避潜在风险。与上面例子不同的是,这里我们无法事先知道有哪些空域需要参与计算,并且空域数量庞大、形状不规则(如下图所示),如果使用轮询的方式套搬上面的方法,会导致计算量过大,无法保证实时性。

这里我们对问题进行拆解,第一步对空域数据进行检索,排除非相关部分;第二步对检索得到的空域进行坐标计算,判断是否为包含关系。

三、地理数据检索

通常使用R树索引对地理数据进行检索,这是一种非精确的索引,利用图形最小包围盒MBR进行快速过滤。

由于R树索引的特性,构建索引时图形粒度越小,检索的效率就会越高。如果将空域作为一个整体构建索引,在检索时会返回较多不相关数据,导致过滤率较低。因此我们转换另一个思路,对构成空域的各个线段进行索引,提升过滤率。

四、射线法计算空间关系

索引细化后,我们无法直接判断点与原空域的空间关系,这里我们改用几何光学里的射线法进行空间计算。
射线法的原理是:从目标点向无穷远处发射一条直线,如果直线与多边形的交点个数为奇数,则该点位于多边形的内部。

结合R树检索与射线法计算过程后,整体算法调整如下:

  1. 从目标点(x, y)到水平无穷远处(∞, y)构建一条直线A;
  2. 利用R树索引检索所有与直线A相交的空域线段;
  3. 使用射线法判断各个空域相交线段的数量,如果为奇数,则目标点位于该空域内。

以上算法的优点是最大限度的利用了R树索引,索引得到的结果即为第三步射线法计算所需要的全集。在实际使用过程中该算法表现也符合预期,例如空域数量10W时,对应空域线段数量在200W左右,经过R树索引过滤后相关线段只有200+。

五、特殊处理

射线法特殊场景

使用射线法判断相交时,有几类特殊场景需要处理,具体如下:

  1. 射线与线段交点刚好为两线段的交接处;

    此时射线同时穿过两线段,但实际交点只有一个。因此在进行相交判断时,需要按左开右闭图形进行计算,同时构成图形的线段数据需要按照有向图排列。
  2. 交点在两线段交接处,且两线段在射线同侧;

    此时虽然射线与线段有交点,但实际并未发生多边形内外区域穿越,这类交点需要排除不纳入统计。
  3. 射线起点在线段上;

    相交的一种特殊场景,可以按正常相交进行计算。
  4. 射线经过平行线;

    同第二种场景,由于未发生内外区域穿越,这类交点同样需要排除。

地理坐标特殊场景

对于地理坐标计算时,当出现坐标跨越换日线时,此时再用平面几何的方式进行计算会出现异常。例如计算点坐标(170, 0)水平射线与线段(170, 10), (-170, -10)是否相交:

在地理坐标系里,坐标之间始终按照劣弧方式进行连接,因此(170, 10), (-170, -10)表示的是跨越换日线的线段,而平面坐标系里则不存在这一限制。此时可以对图形坐标进行水平扩展,例如(170, 10), (-170, -10)转换为(170, 10), (190, -10)。

曲线的计算

上面的计算里将几何图形简化为了直线连接,不过实际计算过程中往往会遇到圆弧连接、大圆线连接等场景,此时需要自行计算其最小包围矩形并加入到R树索引,或采用线段拟近的方式进行拆解。

参考资料:

地理坐标系与投影坐标系辨析
投影类型
Wiki: Point in polygon

阮伟聪

射线法进行地理空间坐标计算相关推荐

  1. 射线法 java_射线法(1190 - Sleepwalking )

    题目:http://lightoj.com/volume_showproblem.php?problem=1190 参考链接:https://blog.csdn.net/gkingzheng/arti ...

  2. c#竖直射线法判断点是否再多边形里面

    一.开发环境: VS2017   C#winform 二.竖直射线法大致介绍 通过被判断的点P(x0,y0)引出竖直的上下两条射线,如果两条射线与多变形的交点都为奇数个,那么这个点再多边形里面,反之, ...

  3. python 判断一个点(坐标)是否在一个多边形内利用射线法

    看了一篇博客写的用射线法判断一个经纬度点是否在一个多边形的内部的方法 经验证可行所以拿来用作备份: class Point:lng = ''lat = ''def __init__(self, lng ...

  4. python内点法_python射线法判断一个点在图形区域内外

    # -*-encoding:utf-8 -*- # file:class.py # """ 信息楼 0 123.425658,41.774177 1 123.425843 ...

  5. JAVA射线_射线法 - 萌德真帅 - 博客园

    射线法 这是一个大佬看了都说简单的算法....(甚至觉得没有掌握的必要) QAQ 这个算法是用来判断一个点是否在一个多边形以内.很简单 将这个点沿着x轴的正方向作射线.如果穿过的边数为基数,那么这个点 ...

  6. python射线法-离线根据经纬度反向获取城市信息

    python射线法-离线根据经纬度反向获取城市信息 准备工作 相关算法储备 总结 目前能够使用 经纬度信息去逆解析经纬度的API有很多,各自可以根据业务需求和地理编码格式选择百度.谷歌.高德等API. ...

  7. 判断坐标点是否处于某个范围内(射线法)

    判断坐标点是否处于某个范围内(射线法) Vue Java 声明 Vue /*** 判断点是否多边形内* @param {Point} point 点对象* @param {Polyline} poly ...

  8. 激光雷达射线法分割地面

    学习记录用,在原博客的基础上增加了一些代码注释和个人理解. 文章目录 前言 一.预处理 1.裁切过高点云 2.消除雷达近身反射点的影响 二.角度微分和地面判断(核心部分) 三.launch文件说明及效 ...

  9. 美图技术博客之地理空间距离计算优化

    http://tech.meituan.com/lucene-distance.html 地理空间距离计算优化 zhan2014-09-05 18:35 1 地理空间距离计算面临的挑战 打开美团app ...

最新文章

  1. 理解事件捕获。在限制范围内拖拽div+吸附+事件捕获
  2. Win7如何改变用户文件夹位置
  3. mybaits十一:使用association分步查询
  4. 爱国者强烈推荐:nanopiR1——你懂的功能,懂你的开发板
  5. 简单的js文本框提示语
  6. java calendar_Java Calendar complete()方法与示例
  7. mysql检索面试题目_MySQL面试题目二十七道整理
  8. winserver2008/2008R2 AD域控/DNS环境搭建详细步骤
  9. Python 爬取必应翻译
  10. PDF翻译神器,再也不担心读不懂英文Paper了
  11. 网站性能优化——雅虎14条
  12. 网络端口扫描器.扫描开放端口.TCP/UDP的Socket通信.支持IP地址网段范围的批量扫描.支持多线程操作,提高扫描效率
  13. 华为手机序列号前三位_华为所有型号交换机查看序列号方法
  14. 按键精灵调用python文件_Python按键精灵自动化
  15. SQLite3:对SQLite3加密
  16. Unity游戏开发 头发飘动效果
  17. Windows系统基础配置
  18. LCP 03 机器人大冒险(分析-计算运动周期)
  19. O3DE 的Lumberyard 游戏引擎
  20. 小米手机v3.exo 合并_eXo Platform 3.0访谈

热门文章

  1. azure mysql数据库_Azure上创建MySql数据库服务
  2. 「镁客·请讲」打造一台眼睛专属“跑步机”,鹰视菲诺是如何用AI拯救近视的?...
  3. 开源自主导航小车MickX4(五)gmapping建图
  4. 智能,服务,生态:华为调制的AIOps,味道有何不同?
  5. 华为核心交换机HW_S7706添加静态路由
  6. 【爬虫】关于企业信用信息公示系统-加速乐最新反爬虫机制
  7. vue实现实时直播 摄像头实现实时直播 dplayer+flv flv.js
  8. 第二类曲线、曲面积分计算公式
  9. 【hadoop生态之Hive】Hive的查询语言【笔记+代码】
  10. realme Q2Pro和红米x10哪个好