根据已知站点寻找路网的最短路径

背景

接上期,基于MATSim的交通仿真,其中有一块非常重要的就是公交的仿真,这也是当初选择MATSim技术路线的一个重要原因,现在业务给出的场景是上传一些有序站点及其经纬度,需要通过算法来适配对应的路网,由于路网只有一套,注意这些站点不一定是路网的的节点,且大多数情况不是,所以需要做2件事情,第一件是将所有站点绑定到路网中对应的link,第二件是在路网中找出一条路线串起所有有序站点,称为绑路,简而言之,一个是绑路,一个是绑站。往往绑路先行,原因后续会论述,这一期,先来聊聊绑路。

思路

经调研发现最短路径往往只支持起点终点为路网中节点的情况,既然有序站点不是路网中的节点,那我先将其映射到路网中的节点,然后再去调用最短路径算法生成任意两点的最短路径,返回经过的link,最后把所有link按先后顺序拼接起来便得到经过所有站点的路径,严格来说是经过所有映射后节点的路径,具体的

1,为每个stop按最近距离法则建立站点到node的映射关系,找到其对应的node,记得node去重(可选),形成映射后的有序node_list;
2,对node_list循环,找出每相邻两个node的最路径,返回segement_node;
3,将所有的segement_node拼接起来形成整个route的route_node;
4,再以route_node去整个路网的link池(link_pool)寻找对应的link_list;

核心代码

def route_schedule(stop, network): #根据有序的站点列表按最短路径构建线路# print(stop, network.edges, network._node)node = {} #用来存放路网的所有节点id及对应的几何对象for (k,v) in network._node.items(): #node_id+xy坐标if bool(v):p = Point(v.get('x'), v.get('y'))node[k] = p# print("\n所有节点\n", node)tree = STRtree(list(node.values())) #利用路网的所有节点构造一个r-treestop_map = {} #用来存放站点映射后的节点,并且以站点的id作为键for (k,v) in stop.items():idx = tree.nearest(Point(v)) #为每个站点找出路网中与该站点最近的节点序号stop_map[k] = list(node.keys())[idx]print('\n每个站点映射后的路网节点\n', stop_map) # stop_map = unique_dict_values(stop_map) # # 此处可以加一个stop_map的相邻相同节点去重# print('\n去重后每个站点最近的路网节点\n', stop_map) path =[] #用来存放经过所有站点的最短路径for i in range(len(stop_map) -1): #对映射后的节点循环len(stop_map) -1start_node = list(stop_map.values())[i]end_node = list(stop_map.values())[i+1]# print("起始节点", start_node, end_node)shortest_path = nx.dijkstra_path(G, start_node, end_node)# print("从起点到终点最短路径", shortest_path)if i == 0: #如果是第一段path.extend(shortest_path)else: #其余的去掉第一个节点path.extend(shortest_path[1:])print("\n最短路径经过哪些节点\n", path)route  = [] #用来存放路线经过的linklink_pool = {} #用来存放路网所有的link的id及几何对象,做成一个link池for edege in network.edges:# print(edege)if network._node[edege[0]] and network._node[edege[1]]:link_id = str(network[edege[0]][edege[1]]['path_id'])link_pool[link_id] = edege# print("\nlink池子\n", link_pool)for i in range(len(path)-1): #根据路径中的node对去link池索引对应的linknode_pair = (path[i], path[i+1]) #node对# print(node_pair)route_link = find_key_by_value(link_pool, node_pair) #根据值找键route.append(route_link)print("\n路线经过的link\n", route)return route

优缺点分析

首先,该方法简单直白高效,在建立站点与节点映射的时候,也会存在多对一的情况,如’557023’: ‘9635081392’, ‘557024’: ‘9635081392’,相邻两个站点对应同一个节点,可以加一个限定对应的节点均为起点,也就是在起点里面找对应点,然后再去重,同时,最短路径找出来的路径应该是连贯的,这么做出来连贯是连贯,但是会形成环路,回路,分路叉支,如下图所示,问题关键应该在站点映射到节点环节出问题了,可以对应的优化,其实,更本质的是"在一个有向图中,如何利用networkx寻找经过有序点的最短路径,这些有序点不一定是节点"的算法构建,可以考虑将这些站点作为节点插入到原始路网中;

效果预览
百度的金泽5路上行

迭代优化思路1

在建立站点与节点映射的时候,很有可能站点及节点经纬度的经度问题出些问题,可以考虑将这些站点作为节点插入到原始路网中,本次围绕这个关键点进行迭代优化

核心代码1

  # 将站点作为虚拟节点插入到图中stop_attribution = stop_df[['stop_id', 'x', 'y']].set_index('stop_id').to_dict(orient='records') #经纬度合并成dictdf_stops = pd.DataFrame({"stop_id": stop_df['stop_id'], "attribution": stop_attribution})network.add_nodes_from((attr['stop_id'], attr['attribution']) for row, attr in df_stops.iterrows()) #Use (node, attrdict) tuples to update attributes for specific nodes.

由于桥接的node没有link接入网络会报错networkx.exception.NetworkXNoPath: No path to 557011.

迭代优化思路2

既然将所有的站点映射到原始路网的节点可能会存在环路,回路,岔路等问题,根本可能站点周边没有合适的节点,所以可以加一个逻辑筛选,如果站点周边150米范围内有节点则进行按最短距离去匹最近的节点,这样一来,有些站点有映射节点,有些站点没有映射节点,而且前者居多,只用有映射的节点的来进行后续的最短路径算法也是可行的。
站点映射出岔子了

核心代码2

 stop_map = {} #用来存放站点映射后的节点,并且以站点的id作为键for (k,v) in stop_dict.items():if any(tree.query(Point(v).buffer(0.0008))): #如果站点周围200米有节点的话print("站点周边200米有节点", [list(node.keys())[idx] for idx in tree.query(Point(v).buffer(0.0008))])idx = tree.nearest(Point(v)) #为每个站点找出路网中与该站点最近的节点序号stop_map[k] = list(node.keys())[idx]print('\n每个站点映射后的路网节点\n', stop_map) 

优缺点分析

一些很容易映射错误的站点消除掉了,但是这个思路是凭借经验值获取的,稳健性不够
旁支消灭了

迭代优化思路3

为了让这个稳健性提高可以让过滤后的节点数占原先的80%及以上,可以增加一个过滤效果的逻辑判定
站点位置位于对面

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/477098.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jenkins + gitee 自动触发项目拉取部署(Webhook配置)

目录 前言 Generic Webhook Trigger 插件 下载插件 ​编辑 配置WebHook 生成tocken 总结 前言 前文简单介绍了Jenkins环境搭建,本文主要来介绍一下如何使用 WebHook 触发自动拉取构建项目; Generic Webhook Trigger 插件 实现代码推送后,触…

leetcode 919.完全二叉树插入器

1.题目要求: 完全二叉树 是每一层(除最后一层外)都是完全填充(即,节点数达到最大)的,并且所有的节点都尽可能地集中在左侧。设计一种算法,将一个新节点插入到一棵完全二叉树中,并在…

SSL协议

文章目录 1. 前言2. 基础概念3. SSL协议结构3.1 概述3.2 SSL握手协议3.3 修改密码说明协议3.4 报警协议3.5 SSL记录协议 4. SSL安全性4.1 安全机制分析4.2 脆弱性分析 5. SSL证书 1. 前言 参考《应用系统安全基础》 2. 基础概念 安全套接字层协议(Security Socke…

Flink-Source的使用

Data Sources 是什么呢?就字面意思其实就可以知道:数据来源。 Flink 做为一款流式计算框架,它可用来做批处理,也可以用来做流处理,这个 Data Sources 就是数据的来源地。 flink在批/流处理中常见的source主要有两大类…

Linux线程_线程控制_线程库

一.线程控制 在Linux操作系统的视角,Linux下没有真正意义上的线程,而是用进程模拟的线程(LWP)。所以,Linux不会提供直接创建线程的系统调用,而是提供创建轻量级进程的接口。但是由于用户只认线程&#xff0…

计算机网络:运输层 —— TCP 的超时重传机制

文章目录 TCP 的超时重传超时重传时间的选择重传策略与拥塞控制的关联 TCP 的超时重传 TCP 的超时重传是保证数据可靠传输的重要机制之一 保证数据可靠性:通过超时重传机制,即使在网络状况不佳,出现数据包丢失等情况时,也能够确保…

C嘎嘎探索篇:和stack,queue的相遇

C嘎嘎探索篇:和stack,queue的再次相遇 前言: 小编在前几日刚完成了关于list容器的介绍,中间由于我牙齿出现了问题所以断更了不少天,如今我牙齿已经恢复,我也要开始继续新内容的讲解了,各位读者…

GPTZero:高效识别AI生成文本,保障学术诚信与内容原创性

产品描述 GPTZero 是一款先进的AI文本检测工具,专为识别由大型语言模型(如ChatGPT、GPT-4、Bard等)生成的文本而设计。它通过分析文本的复杂性和一致性,判断文本是否可能由人类编写。GPTZero 已经得到了超过100家媒体机构的报道&…

MyBatis Plus 项目的创建和使用

1. 快速上手 1.1. 项目的创建和配置 首先&#xff0c;创建一个 Spring Boot 工程&#xff0c;添加 MyBatis Plus 和 MySQL 对应的依赖&#xff0c;然后&#xff0c;和 MyBatis 一样&#xff0c;需要在 yml 文件中配置数据库连接信息 <dependency><groupId>com.b…

IDEA 2024.3 版本更新主要功能介绍

IDEA 2024.3 版本提供的新特性 IntelliJ IDEA 2024.3 的主要新特性&#xff1a; AI Assistant 增强 改进的代码补全和建议更智能的代码分析和重构建议Java 支持改进 支持 Java 21 的所有新特性改进的模式匹配和记录模式支持更好的虚拟线程调试体验开发工具改进 更新的 UI/UX 设…

Java编程,配置mongoUri连接mongodb时,需对特殊字符进行转义

一、背景 java程序连接mongo有两种方式&#xff1a; 用户名和密码方式uri方式 1、用户名和密码 以用户数据库为例&#xff0c;注意看它的密码 spring:data:mongodb:host: 192.168.10.17database: db_user_serviceport: 3717username: user_servicepassword: user_service3…

学习笔记|MaxKB对接本地大模型时,选择Ollma还是vLLM?

在使用MaxKB开源知识库问答系统的过程中&#xff0c;除了对接在线大模型&#xff0c;一些用户出于资源配置、长期使用成本、安全性等多方面考虑&#xff0c;还在积极尝试通过Ollama、vLLM等模型推理框架对接本地离线大模型。而在用户实践的过程中&#xff0c;经常会对候选的模型…

Python 快速入门(上篇)❖ Python基础知识

Python 基础知识 Python安装**运行第一个程序:基本数据类型算术运算符变量赋值操作符转义符获取用户输入综合案例:简单计算器实现Python安装** Linux安装: yum install python36 -y或者编译安装指定版本:https://www.python.org/downloads/source/ wget https://www.pyt…

【1.2 Getting Started--->Installation Guide】

NVIDIA TensorRT DOCS 此 NVIDIA TensorRT 10.6.0 安装指南提供安装要求、TensorRT 包中包含的内容列表以及安装 TensorRT 的分步说明。 安装指南 摘要&#xff1a; 本 NVIDIA TensorRT 10.3.0 安装指南提供了安装要求、TensorRT 软件包中包含的内容列表以及安装 TensorRT 的…

RT_Thread内核源码分析(三)——线程

目录 1. 线程结构 2. 线程创建 2.1 静态线程创建 2.2 动态线程创建 2.3 源码分析 2.4 线程内存结构 3. 线程状态 3.1 线程状态分类 3.2 就绪状态和运行态 3.3 阻塞/挂起状态 3.3.1 阻塞工况 3.4 关闭状态 3.4.1 线程关闭接口 3.4.2 静态线程关闭 3.4.3 动态线程关…

Unity图形学之CubeMap立方体贴图

1.CubeMap&#xff1a;有六个面的贴图组成 2. 假反射&#xff1a;反射天空盒子 &#xff08;1&#xff09;正常UV采样&#xff1a; &#xff08;2&#xff09;Cube的采样&#xff1a;利用反射角采样&#xff0c;反射角X和Cube的交点采样 Shader "Custom/TestReflect"…

C语言基础学习:抽象数据类型(ADT)

基础概念 抽象数据类型&#xff08;ADT&#xff09;是一种数据类型&#xff0c;它定义了一组数据以及可以在这组数据上执行的操作&#xff0c;但隐藏了数据的具体存储方式和实现细节。在C语言中&#xff0c;抽象数据类型&#xff08;ADT&#xff09;是一种非常重要的概念&…

Qt-多元素控件

Qt中的多元素控件 Qt提供的多元素控件有&#xff1a; 这里的多元素控件都是两两一对的。 xxWidget和xxView的一个比较简单的理解就是&#xff1a; xxView是更底层的实现&#xff0c; xxWidget是基于xxView封装来的。 可以说&#xff0c;xxView使用起来比较麻烦&#xff0c;但…

2023年9月GESPC++一级真题解析

一、单选题&#xff08;每题2分&#xff0c;共30分&#xff09; 题号 123456789101112131415 答案 CDBCDBACACBBDDA 1. 我们通常说的 “ 内存 ” 属于计算机中的&#xff08;&#xff09;。 A. 输出设备 B. 输 ⼊ 设备 C. 存储设备 D. 打印设备 【答案】 C 【考纲知识点】…

wend看源码-APISJON

项目地址 腾讯APIJSON官方网站 定义 APIJSON 可以定义为一个面向HTTP 协议的JSON 规范&#xff0c;一个面向数据访问层的ORM 框架。其主要工作流程包括&#xff1a;前端按照既定格式组装 JSON 请求报文&#xff0c;通过 APIJSON-ORM 将这些报文直接转换为 SQL 语句&#xff0c…