基于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. 示例结果

相关推荐
ZhengEnCi12 分钟前
P2M-Matplotlib折线图完全指南-从数据可视化到趋势分析的Python绘图利器
python·matlab·数据可视化
ZhengEnCi2 小时前
P2L-Matplotlib饼图完全指南-从数据可视化到图表定制的Python绘图利器
python·matlab
曲幽2 小时前
你的REST接口还在“过度投喂”数据吗?——FastAPI + GraphQL实战避坑指南
python·fastapi·web·graphql·route·cors·rest·strawberry
用户8358086187913 小时前
基于 Self-RAG 与列表级重排序的进阶 RAG 系统设计与实现
python
Warson_L19 小时前
Python `Annotated` 与 LangGraph Reducer 学习笔记
python
韩师傅19 小时前
海天线算法的前世今生
python·计算机视觉
韩师傅20 小时前
当你的甲方设备过烂,要如何快速出效果?
python·计算机视觉
Warson_L20 小时前
LangGraph的MessageState and HumanMessage
python
韩师傅20 小时前
当你的甲方吐槽天空不够蓝,你应该如何应对
python·计算机视觉
Warson_L21 小时前
python的类&继承
python