基于OSM数据构建交通通行网络图(1/3)

1 构建两条道路空间通行关系判断规则

假设有两条道路A和B,道路A为源道路,道路B为目标道路,实验的目标是判断从道路A出发能否到达道路B。首先根据道路类别建立通行规则,然后根据两条道路的空间拓扑关系判断道路A是否能够通往道路B。

道路空间通行关系规则决策树

1.1 实现方法概述

首先从OSM中获取的路网数据存储了道路类型信息,其将道路分为高速路、快速路、主干道、次干道、其他道路等,并且道路是单向通行的。因此不同道路的通行规则是能够基于道路类型属性快速区分。其次,道路的行车方向与空间线条点集顺序一致,即从第一个点前往最后一个点。最后,影响两条道路通行关系的空间拓扑包括三类:连续(Connected)、接触(Touch)和相交(Intersect),需基于一些算法具体判断道路间的空间拓扑关系。

以下WKT格式表示的道路起点、终点和行车方向如图所示。

text 复制代码
LINESTRING(118.7668063525639 32.05806454085803,118.7667190099296 32.05807233008715,118.7666316672952 32.0580801193163,118.7665443246609 32.05808790854542,118.7664569820266 32.05809569777457,118.7663696393922 32.05810348700371,118.7662822967579 32.05811127623283,118.7661949541236 32.05811906546198,118.7661076114892 32.0581268546911,118.7660202688549 32.05813464392023,118.7659329262206 32.05814243314938,118.7658452646464 32.05814450350625,118.7657576030723 32.05814657386314,118.7656699414982 32.05814864422003,118.765582279924 32.05815071457692,118.7654946183499 32.05815278493378,118.7654069567757 32.05815485529067,118.7653192952016 32.05815692564755,118.7652316336275 32.05815899600444,118.7651439720534 32.05816106636131,118.7650577766283 32.05815226087318,118.7649715812032 32.05814345538508,118.7648853857781 32.05813464989693,118.764799190353 32.05812584440881,118.7647129949279 32.05811703892068,118.7646267995028 32.05810823343255,118.7645406040777 32.05809942794443,118.7644544086526 32.0580906224563,118.7643682132275 32.05808181696818)

1.2 空间拓扑关系判断的特殊情况

  1. 由于OSM数据本身会存在一些误差,比如现实世界中相连接的道路,OSM数据中两条线是不相交的。经测算,两条道路空间拓扑关系判断的空间容差(Tolerance)不超过100m。对于地理学,使用了0.00001米的距离公差(因此非常接近的点被认为是相交的)。
  2. 拓扑关系的不确定性。在二维地图中,相交的道路在实际三维世界中并不一定是相交关系,比如高架桥和地下隧道。

2 技术选型与代码示例

  1. 利用存储Postgresql+PostGIS管理空间数据,neo4j管理道路通行网络知识图谱。

  2. 通过编写python算法实现道路通行知识图的构建,其中关键用到了python sqlalchemy和geoalchemy2访问空间数据库,python neo4j库访问neo4j数据库。

在两条道路空间通行关系判断规则中,需基于道路空间拓扑关系判断以确定两条道路是否可通行。以下利用Python编程实现了指定"源道路"空间接触计算、空间相交计算和给定距离线查询等三个方法。

  • 连接Postgresql数据库
python 复制代码
from sqlalchemy import create_engine, func
from sqlalchemy.orm import sessionmaker

DATABASE_URI = f'postgresql://{username}:{password}@localhost:5432/{dbname}'  # 数据库连接信息
engine = create_engine(DATABASE_URI, echo=False)
# 创建会话
Session = sessionmaker(bind=engine)
session = Session()
  • 空间接触计算

    1. 方法描述:

      ST_Touches --- Tests if two geometries have at least one point in common, but their interiors do not intersect.

      Description: Returns TRUE if A and B intersect, but their interiors do not intersect. Equivalently, A and B have at least one point in common, and the common points lie in at least one boundary. For Point/Point inputs the relationship is always FALSE, since points do not have a boundary.


    2. 示例代码

    python 复制代码
    def get_touch_br(source_br: BaseRoad):
        touch_br_list = []
        touch_res = session.query(BaseRoad, func.ST_AsText(BaseRoad.geom)) \
            .filter(func.ST_Touches(BaseRoad.geom, source_br.geom))
        for br, geom in touch_res:
            touch_br_list.append(br)
            br_geom_list.append(wkt.loads(geom))
        return touch_br_list
    1. 示例结果

  • 空间相交计算

    1. 方法描述

      ST_Intersects --- Tests if two geometries intersect (they have at least one point in common).

      Description: Compares two geometries and returns true if they intersect. Geometries intersect if they have any point in common.For geography, a distance tolerance of 0.00001 meters is used (so points that are very close are considered to intersect).

    2. 示例代码

    python 复制代码
    def get_intersects_br(source_br: BaseRoad):
        intersects_br_list = []
        br_geom_list = []
        # 查询与source_br相交的道路
        intersects_res = session.query(BaseRoad) \
            .filter(func.ST_Intersects(BaseRoad.geom, source_br.geom))
        for br in intersects_res:
            intersects_br_list.append(br)
            br_geom_list.append(wkb.loads(WKBElement._data_from_desc(br.geom.desc)))
        return intersects_br_list
    1. 示例结果

  • 给定距离线查询

    1. 方法描述

      ST_DWithin --- Tests if two geometries are within a given distance.

      Description: The distance is specified in units defined by the spatial reference system of the geometries. For this function to make sense, the source geometries must be in the same coordinate system (have the same SRID).

    2. 示例代码

    python 复制代码
    def get_dwithin_br(source_br: BaseRoad):
        dwithin_br_list = []
        dwithin_res = session.query(BaseRoad, func.ST_AsText(BaseRoad.geom)) \
            .filter(func.ST_DWithin(func.ST_GeomFromEWKB(BaseRoad.geom), func.ST_GeomFromEWKB(source_br.geom), Tolerance))
        for br, geom in dwithin_res:
            dwithin_br_list.append(br)
            br_geom_list.append(wkt.loads(geom))
       return dwithin_br_list
    1. 示例结果

相关推荐
装不满的克莱因瓶2 小时前
链式法则如何传递参数误差 —— 深入理解神经网络中的梯度传播
人工智能·python·深度学习·神经网络·数学·机器学习·ai
Anastasiozzzz2 小时前
从有限状态机到智能体图:传统 FSM 与 Agent Graph的演进
java·人工智能·python·ai
biter down8 小时前
从 0 到 1 搭建 Python 接口自动化测试框架(博客系统实战)
开发语言·python
肖永威9 小时前
Python多业务并行计算框架插件化演进:从硬编码到动态注册
python·插件化·并行计算·动态注册
yz_aiks9 小时前
Linux Jar包配置Systemd自启动实战:从排查到配置全流程
linux·python·jar·自启动·systemd
不知名的老吴9 小时前
线程的生命周期之线程“插队“
java·开发语言·python
xsc69967511 小时前
从零搭建大模型与智能体平台 - 完整技术详解
python
无风听海12 小时前
多租户系统中的 OIDC:Discovery 端点与联合登录的深度实践
后端·python·flask
CTA终结者12 小时前
期货量化主力换月程序怎么移仓:天勤 underlying_symbol 与任务切换
python·区块链
马士兵教育12 小时前
Java还有前景吗?Java+AI大模型学习路线及项目?
java·人工智能·python·学习·机器学习