转自:http://blog.jobbole.com/86633/

地理围栏(Geo-fencing)是LBS的一种应用,就是用一个虚拟的栅栏围出一个虚拟地理边界,当手机进入、离开某个特定地理区域,或在该区域内活动时,手机可以接收自动通知和警告。如下图所示,假设地图上有三个商场,当用户进入某个商场的时候,手机自动收到相应商场发送的优惠券push消息。地理围栏应用非常广泛,当今移动互联网主要app如美团、大众点评、手淘等都可看到其应用身影。

图1 地理围栏示意图

地理围栏的核心问题就是判断用户是否落在某多边形围栏内部。本文将介绍实际应用中常用的解决方法。

1 如何判断点在多边形内部

地理围栏一般是多边形,如何判断点在多边形内部呢?可以通过射线法来判断点是否在多边形内部。如下图所示,从该点出发沿着X轴画一条射线,依次判断该射线与每条边的交点,并统计交点个数,如果交点数为奇数,则在多边形内部(如图3个交点),如果焦点数是偶数,则在外部,射线法对凸和非凸多边形都适用,复杂度为O(N),其它N是边数。源码可参考(http://alienryderflex.com/polygon/

图2 射线法判断点在多边形内外

当地理围栏多边形数目较少时,我们可以依次遍历每一个多边形(暴力遍历法),然后用射线法进行判断,这样效率也很高。而当多边形数目较多时,比如有10万个多边形,这个时候需要执行10万次射线法,响应时间达到3.9秒,这在互联网应用几乎不可忍受。下表是本人的简单测试,多边形边数均为7。

表1 射线法性能测试

2 R树索引加速判断

暴力遍历法效率低下的原因是与每一个多边形都进行了射线法判断,如果能减少射线法的调用次数性能就能提升。因此我们的优化思路很直接,首先通过粗筛的方法快速找到符合条件的少量多边形,然后对粗筛后的多边形使用射线法判断,这样射线法的执行次数大大降低,效率也能大大提高。怎么粗筛呢?对于一维数据我们常常使用索引的方法,比如通过B树索引找到某一个范围区间段,然后对此范围区间段进行遍历查找,对于二维空间数据常常使用空间索引的方法,比如通过R树找到范围区间内的多边形,然后对此范围内的多边形进行精确判断,下面介绍最常使用的空间索引R树的解决思路。

       1)外包矩形表示多边形

由于多边形形状各异,我们需要以一种统一的方式来对多边形进行近似,最简单的方式就是用最小外包矩形来表示多边形。

图3 最小外包矩形(MBR)表达多边形

      2)对最小外包矩形建立R树索引

图4 对最小外包矩形进行R树索引

        3)查询

a)首先通过R树迅速判断用户所在位置(粗红点)是否被外包矩形覆盖(图5,红色点代表用户所在位置;R树平均查询复杂度为O(Log(N)),N为多边形个数);

b)如果不被任何外包矩形覆盖则返回不在地理围栏多边形内;

c)如果被外包矩形覆盖则还需要进一步判断是否在此外包矩形的多边形内部,采用上文提到的射线法判断(图2)。

图5 R树查询示例

3 多边形边数较多怎么办

大多数应用的地理围栏多边形都比较简单,但有时也会遇到一些特别复杂的多边形,比如单个多边形的边数就超过十几万条,这时候对此复杂多边形执行一次射线法也非常耗时(因为射线法时间复杂度为O(N),N为多边形边数)。如何提高射线法的计算效率呢?同样使用R树索引!笔者在实际应用中对边数较多(如超过1万)的多边形的边再单独进行R树索引,这样射线法求交点的时候首先通过R树快速粗筛得到符合条件的边,然后对粗筛后的边进行精确求交判断,这样大大提高了计算效率。

4 实践

某线上应用服务有30万个地理围栏多边形,通过在内存中构建R树索引,使得线上实时地理围栏查询平均响应时间在1ms以内,而暴力查询响应时间是9秒左右。

5 R树相关源码

https://pypi.python.org/pypi/Rtree/ (Python)

http://jsi.sourceforge.net/ (Java)

https://github.com/leaflet-extras/RTree (Javascript)

http://sourceforge.net/p/cspatialindexrt/code/HEAD/tree/ (C#)

Geo-Fence的更多相关文章

  1. tile38 一款开源的geo 数据库

    tile38 是基于golang 编写的geo 数据库,支持地理空间索引.实时地理围栏,同时也支持leader-flower 的部署模型 备注: 下边测试一个简单的地理围栏功能 环境准备 docker ...

  2. [LeetCode] Paint Fence 粉刷篱笆

    There is a fence with n posts, each post can be painted with one of the k colors. You have to paint ...

  3. Windows Azure Storage (17) Azure Storage读取访问地域冗余(Read Access – Geo Redundant Storage, RA-GRS)

    <Windows Azure Platform 系列文章目录> 细心的用户会发现,微软在国外和国内的数据中心建设都是成对的,比如香港数据中心(Asia East)和新加坡的数据中心(Sou ...

  4. poj 3253 Fence Repair

    Fence Repair Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 42979   Accepted: 13999 De ...

  5. CF 484E - Sign on Fence

    E. Sign on Fence time limit per test 4 seconds memory limit per test 256 megabytes input standard in ...

  6. poj3253 Fence Repair

    http://poj.org/problem?id=3253 Farmer John wants to repair a small length of the fence around the pa ...

  7. redis geo 初探

    redis的geo搜索功能是3.2之后新增的,所以实验开始之前先查看redis的版本,确保版本正确. redis的geo多用于地理类应用,所以这次还是用了高德地图API来用作数据源. 首先截取几个点: ...

  8. Redis Geo: Redis新增位置查询功能

    转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/144.html 移动互联网增进了人与人之间的联系,其中基于位置信息的服务( ...

  9. nginx利用geo模块做限速白名单以及geo实现全局负载均衡的操作记录

    geo指令使用ngx_http_geo_module模块提供的.默认情况下,nginx有加载这个模块,除非人为的 --without-http_geo_module.ngx_http_geo_modu ...

  10. CF448C Painting Fence (分治递归)

    Codeforces Round #256 (Div. 2) C C. Painting Fence time limit per test 1 second memory limit per tes ...

随机推荐

  1. (五)、nodejs使用bootstrap的样式进行分页

    一.page方法 /****************************************************** * Created User: * Created Time: 201 ...

  2. Sqlserver2005附加数据库为只读的解决方法

    在sqlserver2005中附加数据库时,附加的数据库会变成只读的,只能进行查询操作. 解决方法 1 打开SqlServer Configuration Manager   开始->Micro ...

  3. Windows Server 2003搭建FTP服务器 实现盘符之间切换

     Serv-U中设置虚拟目录的方法 如果在E盘下有一个名为LoveHina的目录,在F盘下也有一个名为LoveHina的目录.那么,如何让使用同一个账号的用户可以同时访问这两个目录呢? 我们可以使用S ...

  4. windows服务器记录3389远程桌面IP策略

    以下代码复制存成一个批处理文件后双击即可! 3389IP日志路径是C:\WINDOWS\PDPLOG\RDPlog.txt  代码: MD C:\WINDOWS\PDPLOG  " /f  ...

  5. C++实现01串排序

    题目内容:将01串首先按长度排序,长度相同时,按1的个数从少到多进行排序,1的个数相同时再按ASCII码值排序. 输入描述:输入数据中含有一些01串,01串的长度不大于256个字符. 输出描述:重新排 ...

  6. VPN连接失败

    连接VPN是总提示 本来我以为是VPN服务器的问题,可是别人就能连接成功,所以只能是我自己机子的问题.后来检查了一下连接属性,终于发现了问题: 这里“允许使用这些协议”应该是处于选中状态,而我的属性里 ...

  7. FileOutputSream

    package cd.itcast.fileinputstream; import java.io.File; import java.io.FileNotFoundException; import ...

  8. Moses更改权重的命令变化 -d -t -

    -l  可以用: weight-l 或者lm  (不需要在前面加-)   还是用-weight-overwrite “Distortion0= 0"更保险 reording weight i ...

  9. Html5 Canvas一个简单的画笔例子

    相比了下Qt quick的canvas和HTML5的canvas,发现HTML5 Canvas在同样绘制绘制操作下性能比Qt的canvas强很多,附上一个HTML5 canvas画笔一例子 var D ...

  10. button与submit

    原文来自: http://blog.sina.com.cn/s/blog_693d183d0100uolj.html submit是button的一个特例,也是button的一种,它把提交这个动作自动 ...