让经纬度数据带矢量方向_惊艳!这样处理可得到细至可用于交通模型的路网数据...

【本期看点】

矢量路网数据哪里来? 对着卫星图一笔一划描? 从AutoCAD转换? 从OSM直接下载? 不,以上方法已经OUT了, 不是效率低,就是误差大,获取局部道路数据勉强可行,但是要获取大片区域的路网数据时就行不通了。

本教程将教你如何利用高德导航接口获取城市矢量路网数据,并剖析路段之间的空间拓扑关系,然后通过OGC空间算法批量处理该关系,最终得到详细至可直接用于交通模型的路网数据。

作者:许新昆 北京交通大学
交通运输和计算机双职称工程师
上得了工地,下得了0/1
致力于用Coding让交通更智能 为什么写这个教程 a80f175f0f718289eda416b96bd6a476.png 如果你做城市规划或者交通规划,需要一个城市的交通路网矢量数据;如果你做交通设计、交通仿真或者交通模型,那么不但需要路网矢量数据,还需要确保道路的方向、连通性等拓扑问题准确无误;如果你做交通评价,还进一步需要各路段的历史和实时路况以及自由流车速。本教程将介绍在没有任何数据的情况下,如何徒手获得这些数据。 常见的获取道路矢量数据的方法有三种,一是在没有任何数据的情况下直接对着卫星图把道路一条一条描出来;二是基于已有的道路CAD数据,逐条设置道路的方向和连通性;三是下载OSM等开源地图,同样也得需要修复方向和连通性。以上三种方法,需要重复的人力劳动,不但效率低,正确率也难以保证。 前段时间在做某地级市交通模型的时候,就有获取整个城市路网的需求,于是花了不少时间仔细研究了高德官方免费的导航接口(官网上叫做”路径规划”,由于”导航”叫法更通俗易懂,后文简称”导航”)。高德官方只对接口返回规范做了解释,对路段的空间关系并没有任何说明,事实上,接口返回的原始路网数据不但在连通性方面有一些问题,而且在不同的时间用完全相同的参数调用接口,返回的路网坐标(经纬度)会稍有偏差,这些原因就导致路段连通性完全断裂,无法建立理想的拓扑关系。如果你获取了路网只是用来展示,那问题不大,但是如果想直接导入交通仿真模型等软件,那在连通性和拓扑性方面就会出大问题。 因此在获得高德导航接口返回的原始路网数据之后,我们还需要进行手动加工,才能满足交通模型对路网连通性和拓扑性方面的要求。通过分析对比,我总结出一系列空间规则,并将这些抽象规则的识别和处理完全代码化,最终解决以上所有问题,得到几乎完美的路网数据。得到的路网数据可以直接导入到交通模型中作为基础路网,极大地节约了构建路网模型的时间,而且准确率极高,时效性几乎无敌。 因此编写本教程向大家分享接口背后”隐藏”的路段空间关系,以及如何识别和处理路段空间关系,以帮助大家获取”完美”路网。 本教程包括以下几个部分: 1. 案例效果图,先看看实际应用场景和效果; 2. 技术方案; 3. 知识和软件储备; 4. 详细的操作实例; 5. 源代码技术架构简介

1 案例效果图

a80f175f0f718289eda416b96bd6a476.png  案例1  来个我见过的最复杂的互通,北京西直门立交桥,因为其交通组织过分复杂,被戏称为”第九奇迹”。第一张图是网络地图,第二张图是处理完之后得到的道路矢量数据,连通性和方向也已经处理好,我在每条路段的终点画一个红色箭头,用来示意路段的方向和拓扑关系。

PS:在这附近上学曾无数次迷路,

毕业后终于靠写代码把路给走通了。

70256d742cbbda05657f3c9b4a010148.png

5013ceee82d54cefca5a45584dcc39f3.png

 案例2  来个普通的十字信号交叉口。各方向均可通行,中间十字交叉的”四条线”代表四个进口道的左转,眼睛看上去是两条线,实际上是四条,一个箭头代表一条线,一条线首尾都有箭头是因为两条线完全重叠了,只不过他们的方向刚好相反。

7ccd743fa84ebd71df45653b5fc4478a.png

 案例3  最后来个环岛,这个很容易看懂,我就不多说了.

11e31fcaef5408cd84d7dad8f75c30e2.png

 2 技术方案

a80f175f0f718289eda416b96bd6a476.png 本教程的技术方案简单来说分为4个步骤: 1. 在ArcMap中画几个OD点对(起点—终点)作为导航的起终点。当然你也可以用已有的带经纬度的POI自己去批量构造OD点对;  2. 用JAVA或PYTHON等语言反复调用高德导航接口,将接口返回的所有路段数据做连通性检查和处理,并转换为OGC标准格式(GeoJson、WKT等)后保存到空间数据库; 3. 在空间数据库中利用SQL和存储过程对路段重复、方向、连通性等一些列问题进行识别和处理,需要用到OGC空间操作符(函数); 4. 导出处理好的路段数据为 .SHP格式,供其它软件如TransCAD、EMME使用。

 

3 知识和软件储备

a80f175f0f718289eda416b96bd6a476.png 1 申请自己的高德路径规划API的key,大家可自行上官网申请。目前这个接口是免费的,并且每天免费调用次数相当多;只要高德手机APP能够导航到的地方,就能用这个接口;高德路网更新很及时,用这种方法得到的路网是最新数据。 2 了解高德导航接口,即高德路径规划API的详细规则,官网地址如下,只需看驾车路径规划部分: https://lbs.amap.com/api/webservice/guide/api/direction 除了官网说明,我补充强调几点:
  • 一次导航可以得到多个方案,因为你从地点A去地点B有很多种走法,殊途同归,每种走法对应一种方案;

  • 一个方案有多个step,比如从你家去单位,先上路A,走到头了右拐进入路B,再右拐进入路C,右拐到D,最后发现今天没上班右拐回了家。这里的ABCD就分别是一个step,每个step长度为大几十米到几百米不等,路比较长的时候一条路会有多个step,对于每一个step,高德给出如下信息:

d088ee784dc29cc187b4960c3739a9cb.png

ACTION: 意思是在这条路的终点驾驶员要采取什么动作; DISTANCE: 这段step的长度,单位是米; DURATION: 驾车通过这段路的时间,单位是秒。应该注意到,把DISTANCE除以DURATION就可以得到这段路的速度,这个很有用,可以写代码实现定时x分钟爬取这条路,爬个一天的数据就可以知道这条路的什么时候堵,还可以计算它的自由流速度,有时间我再另讲这个,这里先不展开讲。 ORIENTATION: 道路方向; ROAD: 道路名称;POLYLINE:路段矢量数据, 一条道路由多个经纬度点构成。
  •  一个step又被拆成多个tmc,从坐标上来看,多个tmc依次首尾相接完全相加等效于step,每段tmc长度一般只有小几十米,除了有以上字段外(没有给出DURATION),tmc还多了一个STATUS信息,即路段拥堵信息,取值为:畅通、缓行、拥堵、未知。本教程构建路网模型只用到tmc路段。

3 安装ArcMap软件,用于描点以及路段的展示;  4 会用Java或者Python等语言进行批量接口调用,并保存路段数据至空间数据库;  5 安装空间数据库,如Oracle、PostSQL、Mysql等,用来保存路段数据,并进行后期处理。 6 对空间数据OGC规范及空间关系判断与操作有一定了解,相关标准可参考: http://www.gismanual.com/relational/99-049_OpenGIS_Simple_Features_Specification_For_SQL_Rev_1.1.pdf

4 操作实例

a80f175f0f718289eda416b96bd6a476.png 为方便大家理解,我以福州市某信号交叉口(高德经纬度为:119.25,26.05)为例,教大家如何一步一步操作,得到最后想要的数据。 本实例开发语言为Java,数据库用Oracle。当然你也可以选择其他语言或数据库,不管用哪种语言,业务逻辑和数据规则都是一样的,因此下文会着重讲解方法和思路,而不是具体的语法。对语法感兴趣的,可以直接读源代码。

1 构造OD点对 

1.1 描点

如图,在ArcMap中新建点图层,并添加软件自带底图(ArcGIS底图默认为高德坐标系)。然后参照底图在道路四个进口道上分别描两个点(图上为红色的×),马路两边是分开的,因此一边描一个,共8个点。  

d1bd8a7630316af2fe0c4cd828f1c7ec.png

28c1755e967ebc82cda8d00ef3d91b3b.png

1.2 生成起终点坐标

将点图层导入到空间数据库,提取这8个点的坐标,将其排列组合得到共计A(8,2)=56组OD点对,用于下一步的导航,部分OD点对如下图。

1ef8b480ca56b923c764636ac06ebbf9.png

2 建立空间表 

在空间数据库中新建表,用于保存道路数据,表字段及各字段存储内容参考如下:

3c77fbdc5924f5fe61e58a77017aeff5.png

其中,polyline 即路段矢量数据是我们最关心的,在Oracle中默认字段类型为SDO_GEOMETRY,在PostSQL中默认字段为Geometry,切记为该字段建立空间索引,因为后期涉及到大量复杂的空间数据处理,有索引跟没索引情况下的计算时间会差上百倍! 

 3 调用路径导航接口 

3.1 发送请求

根据高德路径规划的接口规则,结合上述OD点对坐标,构造56次导航请求参数,依次调用高德路径规划API接口,API参数可参考下图。

a2b1f9910e7a13a0e5a48d2fd13748e5.png

3.2 保存路段数据

将接口返回的路段经纬度信息转换为GeoJson或WKT等标准空间数据格式(具体转换成哪种格式取决于你的数据库类型),并与道路名称、路况等其它字段一起保存至数据库,共计约1000条记录(路段),展示其中一条tmc记录如下图。

1a87de0878e8ee6e851cf26e02b56175.png

有两点需要注意: 1 由于我们选取的起点或者终点不能完全落在高德的路网上(而是落在某条路的附近),因此必须忽略(即不保存)每个路径规划方案中的第一个tmc和最后一个tmc(什么是tmc请查看前文),否则在后面的拓扑关系处理中会出现瑕疵。当然了,如果你只做路网展示,不要求路网的连通性100%正确,这一步可以无视。 2 在绝大多数情况下,该接口返回的多个tmc路段是头尾连续的,但是在信号交叉口左转、调头以及一些匝道出入口等交通组织较为复杂的情况下,路段不连续,为严格保证路段连通性,需要写代码及时判断并自动补线,即在断开的地方补上一条直线。下图以交叉口左转为例做个对比,“补线前”是默认路段数据,“补线后”是利用代码修复连通性后的路段数据。在这个例子中,补的线用来给车辆左转。  

f882eeab2407bc18c54435702828c8b0.png

819ea00e190060f89a37e2724fcb82ab.png

 4 处理路段数据 

从上面步骤可知,导航了56次就产生了约1000条路段,这么小一个交叉口为什么有会这么多路段!? 我们先回头数一下上面”补线后”这张图,里面一共还不到20个箭头,对应只有约20条路段,也就是说1000条路段里面只有20条是最终我们想要的。 想要编程筛选出这20条路段,需要对这1000条路段之间的空间关系规则有深刻理解,高德API官网没有对这种抽象的规则进行任何解释,我花了整整两个星期时间才厘清其中的规律,并编程实现了路段的批量识别和处理,这种关系规则比较抽象,很难光靠文字说清,我在下文尽量讲的通俗易懂。 简单来说,就是对空间表做笛卡尔乘积,比较两辆路段之间的空间关系,并进行相应处理。需要处理的关系主要包括 删除重复道路、处理道路覆盖、增加交叉口调头、纠正路段起终点、删除伪节点这5种,下面逐一讲解。

4.1 删除重复道路

这点很容易想到,1000条路段里面肯定有很多是重复的。问题是怎么筛选并删掉重复的路段? 处理方法:利用OGC规范的EQUALS操作符判断两两路段是否相同(路段由多个经纬度点构成,两路段的所有经纬度点都相同才满足EQUALS关系)。另外,EQUALS操作符不会对路段的方向进行判断,因此需要额外判断路段的起终点也分别相同,即判断条件有三个: a 路段1和路段2满足EQUALS关系; b 路段1的起点和路段2的起点相同; c 路段1的终点和路段2的终点相同; 处理效率方面:对1000条路段进行去重操作,执行时间不到1秒,另外,我之前对400多万记录(路段)的表进行该操作,执行时间也不到10秒。再强调一次,一定要对空间字段建立索引,不然等到天黑都跑不出结果。

4.2 处理道路覆盖

一条较长的路完全覆盖了一条较短的路,注意是完全覆盖,而不是部分覆盖,这种关系可用OGC规范的COVERS操作符进行判断。对于满足COVERS关系的两条路,将长的一条更新为长的比短的多的那部分,短的那条则不变,最后留下的还是两条路段,只不过长的那条变短了,将它称之为”裁剪路段”,示意图如下。

1677290ae13c842c04e946587960995c.png

4.3 增加交叉口调头

对于上一步中产生的”裁剪路段”,将其复制后反转,作为交叉口调头车道,如下图所示,新增的调头车道a供路段1上的车辆调头行驶到路段2。同理,对交叉口的每个进口道做同样处理。如果你的路网模型不考虑车辆调头,可以忽略该步骤。  

fc5c6ee75abe6bca46ab4211b2bdcad5.png

4.4 纠正路段起终点

为什么要进行起终点纠正? 举例说明:路口由西向东的右转车道并入直行车道,照理说只有一个汇合点,但是把汇合点放大后发现,有两个汇合点,并且这两个汇合点相距只有0.3米;而且路网存在偏移重复,即远远看上去只有一条路,放大了看其实有两条,他们位置有一些偏移,不满足完全重复关系。  

05378cce5534263ae5cfe58c8d1bb342.pngbaba171ecc8774d05fca80c68f3f856b.png

高德官网对这个问题的产生原因表述如下:“由于道路/数据/算法的变更,很可能存在间隔一段时间后请求相同起终点的经纬度返回不同结果。” 补充一下,不是”很可能”,而是”大多数时候如此”。也就是说,相同的一条路段,你在不同时间调用会得到不同的坐标,虽然肉眼来看它们挨得很近,但是对于计算机来说,别说1米,就算只差1毫米,那都算不同的两条路。通过大量观察,这种在现实世界中是同一条路但是坐标不同的两个路段,其路段起点(终点)相差不超过1米,因此处理逻辑如下: a 以某路段1的起点为基准,找到距离它小于1米的其它路段2、3、4...的起点,将路段2、3、4...的起点坐标更新为基准点坐标; b 把上一步的起点全部换成终点,然后执行相同的操作; c 以上两步操作会产生重复路段,需再次删除重复道路 处理后效果图如下,可以看到,偏移路段消失了,只留下唯一版本的路段。

8d15b6d47e84af61fc69b1541646f12c.png

4.5 删除伪结点

先用一张图示意什么是伪节点,如下图所示,每条路段的终端用箭头表示,假设车辆行驶至路段a的终点处(结点1)产生了分叉,在该点可以直行进入路段b,也可以右转进入路段c,在该结点存在多余两条的路段(此处是3条),因此该结点不是伪节点; 加入车辆右转进入路段c,并行驶到了路段c的终点(节点2), 在节点2有分叉么? 没有,只能继续行驶到路段d,也就是说该节点处只有两条路段,并不会产生分叉,这种节点就叫做伪节点。

4df21a4a407c44fe72a2b50a8cfdf64d.png

伪节点的存在有意义吗? 没意义,而且很多交通模型、仿真软件(如TransCAD、EMME)对导入路网的节点数量有限制,伪节点过多不但造成资源浪费,还徒增后期的交通模型的计算量,因此最好在构建路网初期就将其删除。 如何识别并删除伪节点:删除伪节点2也即合并路段c和路段d,产生一个新的路段e。路段c与路段d的关系满足: 1 两者关系符合OGC规范的TOUCH关系; 2 c的终点和d的起点重合; 3 在该节点处只存在两条路段 讲到这里顺便提以下ArcGIS的自带的拓扑处理工具,该工具可以删除单向路段上的伪节点,但是在双向路段上该工具失效,所以我自己写了删除伪节点(合并路段)的存储过程,对单向和双向道路都适用。

4.6 导出空间数据

从空间数据库中导出空间表,保存成 .SHP 数据,毕竟几乎所有交通软件都支持这种数据标准。

e71de9982292b8fe5d3974c58e1a2600.png

 

5 项目源代码

a80f175f0f718289eda416b96bd6a476.png 技术架构简介:本项目编程实现分为JAVA和ORACLE两部分。
  • JAVA部分:

JAVA用于爬取高德路径规划接口,进行简单连通性处理,并保存路段数据至空间数据库。 持久化框架:hibernate。使用hibernate中间件进行空间路段数据存储,实现编程和空间数据库软件的分离,即不需要修改源代码,只需修改一两行数据库的配置信息,即可和你的数据库(非Oracle,如PostSQL或MySQL)无缝衔接。 项目构建工具:maven 空间数据工具包:JTS
  • Oracle部分:

Oracle空间数据库用于存储路段数据,并对路段进行方向、连通性等拓扑处理,包括SQL语句,以及存储过程。 版本:oracle 11.2,更高版本也支持(Oracle XE除外)。 空间字段格式:SDO_GEOMETRY Talking is Cheap,Show me the Code。本项目源代码已在github上开源,关注城市数据派微信号,在微信号中输入“ 0527 ”,即可获得github上的代码地址,欢迎大家参考、交流和使用。 有任何问题欢迎与本文作者交流。 微信:xuxinkun0591 邮箱:xuxinkun@189.cn

0dabd47f85faf985678f52e3d7db3a5a.png

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值