1.思路:

1.抽取路网(管网)各节点,点去重+点线关联;---根据数据及业务场景可选择线起始点/起中终点/全部节点;

2.构建路网(管网)各节点KDtree;

3.使用邻接矩阵存储点连通性;--不通:-1、自身点:0、相连:1(或权重/距离--可根据业务场景设置);

4.基于KDtree分别捕获到 [ 出发点 , 到达点] 最近的一个捕捉节点(k=1);

5.根据捕捉节点进行图的广度优先遍历--结合迪杰克斯特拉(Dijkstra)算法思路--因为节点重复,根据节点键值取存储线id后,需要根据前后节点筛选线;

6.前进方向确定(线遍历后排列顺序+线坐标点集合顺序)--根据返回数据格式确定;

7.路书制作( 八方位-["北", "东北", "东", "东南", "南", "西南", "西", "西北", "原点", ]+ 下一节点方向(左/右/直行/掉头))--方向-八方位-坐标大小/ 方向-左右-向量叉乘(注意:当前代码因数据区域大小原因,已忽略椭球体及地理坐标影响因素);

8.结果输出(在路书中增加出发点/到达点与最短路径的关系--详细导航信息)--当前输出json结构参考了高德最短路径分析api返回数据结构;

9.效率优化--(将数据提前加载进内存/api调用)--当前框架使用python/flask,一秒内返回结果(当前测试数据大概0.04-0.5)

2.实现

1.python

#!/usr/bin/python3
# -*- coding:utf-8 -*-'''
####################################################################################
#版本信息
##最近修改时间:20220331
##最近修改人:慢慢
####################################################################################
#功能说明
##路径分析
####################################################################################
#返回结果
##返回格式-dict
##运行成功-
##运行失败-{"code": 404, "type": "fail", "msg": "服务错误", "box": "", "data": "需要重启"}
####################################################################################
#使用说明
####################################################################################
#更新历史
##20220421 新增最短路径导航详细信息 路书功能开发-(路口左右转、东南西北八个方向、距离)
####################################################################################
'''import json
from shapely.geometry import LineString
from shapely.geometry import mapping as geommapping
# from lib.geotools import Features, Intersect, Clip, ToPolygons, CreatGrid, ToPoints
try:from lib.flaskservices.config_app import __keyself__
except ImportError:__keyself__ = {"file_line": "/data/l_road.shp","building": "/data/r_building.shp", "grid": "/data/r_grid.shp","people": "/data/r_people.csv"}
from geopandas import GeoSeries, GeoDataFrame__data__type = (list, tuple)
__mapdata_type__ = (GeoSeries, GeoDataFrame)
__kself__ = list(__keyself__.keys())[0]def GetRoadBookCourse(pointa, pointb):# 方向-八方位-坐标大小txt = ["北", "东北", "东", "东南", "南", "西南", "西", "西北", "原点", ]x_p, y_p = round(pointb[0], 4) - round(pointa[0], 4), round(pointb[1], 4) - round(pointa[1], 4)if x_p == 0 and y_p > 0:course = txt[0]elif x_p > 0 and y_p > 0:course = txt[1]elif x_p > 0 and y_p == 0:course = txt[2]elif x_p > 0 and y_p < 0:course = txt[3]elif x_p == 0 and y_p < 0:course = txt[4]elif x_p < 0 and y_p < 0:course = txt[5]elif x_p < 0 and y_p == 0:course = txt[6]elif x_p < 0 and y_p > 0:course = txt[7]else:course = txt[-1]return coursedef GetRoadBookLR(origin, pointa, pointb):# 方向-左右-向量叉乘x_o, y_o = round(pointa[0], 2) - round(origin[0], 2), round(pointa[1], 2) - round(origin[1], 2)x_l, y_l = round(pointb[0], 2) - round(origin[0], 2), round(pointb[1], 2) - round(origin[1], 2)k = (x_o * y_l) - (x_l * y_o)if k < 0:lr = "右转"elif k > 0:lr = "左转"else:# 左右-向量点乘k = (x_o * x_l) + (y_o * y_l)if k < 0:lr = "掉头"else:lr = "直行"return lrdef GetNodeInd(kdtree, point, k=1):try:__distances, __ind = kdtree.query(point, k=k)return True, __indexcept:return False, "根据输入点获取最近线失败(经度,纬度) " + "%s" % point# 因为节点重复,根据节点键值取存储线id后,需要根据前后节点筛选线
def GetNodeIdLineId(poiss_ind, adjacency_matrix, node_dict, node_key):# 广度优先遍历--结合迪杰克斯特拉(Dijkstra)算法思路try:loop_will = [poiss_ind[0]]loop_ed = set()loop_done = []loop = 0loop_stdout = [poiss_ind[1]]stdout = []while loop_will:loop = loop_will.pop(0)loop_once = []loop_ed.add(loop)for i, lind_id in enumerate(adjacency_matrix[loop, ...]):if lind_id > 0:loop_once.append(i)if i == poiss_ind[1]:loop_will.clear()loop_stdout.append(loop)breakif i not in loop_ed:loop_will.append(i)else:loop_done.append([loop, loop_once])loop_done.reverse()for key in loop_done:if loop in key[1]:loop_stdout.append(key[0])loop = key[0]if loop == poiss_ind[0]:loop_stdout.reverse()break################################################################################## 可运行,可用于功能扩展# while loop:#     for key in keys:#         if loop in loop_done[key]:#             loop_stdout.append(key)#             loop = key#         if loop == poiss_ind[0]:# #             loop_stdout.append(key)#             loop_stdout.reverse()#             loop = 0#             break################################################################################## 确定前进方向for key in loop_stdout:stdout.extend(node_dict[node_key[key]])else:stdout = list(set([v for v in stdout if stdout.count(v) > 1]))# 根据图遍历结果数据特性--间隔取值,逆间隔取值--转换到最终结果if len(stdout) > 2:stdout = stdout[1::2] + [stdout[-1]] + stdout[-3::-2]except Exception as __ex:return False, "路径搜索失败:GetLineId()" + "%s" % __exelse:return True, (loop_stdout, stdout)def SetOutFormatGD(poiss, nodeid_lineid, node, line, to_crs=4544):def GetBook(poi, p_l, roadname, length):if not roadname:roadname = "无名道路"data["points"].extend(p_l)tmp = dict()tmp["instruction"] = "\tGetRoadBookLR\t.沿" + roadname + GetRoadBookCourse(poi[0],poi[1]) + "方向前进 %s" % round(length, 2) + " 米,\tGetRoadBookLRNext\t;"tmp["points"] = p_ldata["steps"].append(tmp)data = {"steps": [], "points": []}for i, id in enumerate(nodeid_lineid[1]):points = list(geommapping(line["geometry"][id])["coordinates"])if node[nodeid_lineid[0][i]] != points[0]:points.reverse()if i == 0:poi = [list(poiss[0]), points[0]]p_l = poiroadname = "出发点到最近路口的"length = GeoDataFrame(crs=to_crs, geometry=[LineString(poi)]).length[0] * 100000else:poi = [points[0], points[-1]]p_l = pointsroadname = str(line["Name"][id]).replace("None", "")length = line["Shape_Leng"][id]GetBook(poi, p_l, roadname, length)else:poi = [points[-1], list(poiss[1])]p_l = poiroadname = "最近路口到达点的"length = GeoDataFrame(crs=to_crs, geometry=[LineString(poi)]).length[0] * 100000GetBook(poi, p_l, roadname, length)# 路书for i in range(len(data["steps"])):if i == 0:# 正北方向origin = [list(poiss[0])[0], list(poiss[0])[1] - 1]pointa = data["steps"][i]["points"][0]pointb = data["steps"][i]["points"][1]lr = ",准备出发"insed = "到达主路"elif i == len(data["steps"]) - 1:origin = data["steps"][i]["points"][-2]pointa = data["steps"][i]["points"][-1]pointb = list(poiss[1])lr = ",到达目的地附近"insed = "到达目的地"else:origin = data["steps"][i - 1]["points"][-2]pointa = data["steps"][i]["points"][0]pointb = data["steps"][i]["points"][1]lr = ""insed = "下个路口" + insins = GetRoadBookLR(origin, pointa, pointb)data["steps"][i]["instruction"] = data["steps"][i]["instruction"].replace("\tGetRoadBookLR\t",ins + lr).replace("\tGetRoadBookLRNext\t", insed)return dataclass AnalysisPath:def __init__(self, data_dict):self._type = Trueself._msg = {"code": 200, "type": "success", "msg": "最短路径分析成功", "box": "", "data": None}self.data_dict = data_dictdef __str__(self):return 'AnalysisPath类实现路径分析'def __Check(self, data):if data[0]:return data[1]else:self._type = Falseself._msg = {"code": 204, "type": "fail", "msg": "最短路径分析失败", "box": "", "data": "%s" % data[1]}return Nonedef Run(self, crs_distance=4544):# ######################################################################################################### # # 可运行--计算两点直线距离,以后功能扩展可用# pois = [self.__Check(v) for v in#         [ToPoints(data=[v], crs=self.data_dict[__kself__].crs).XYs() for v in#          self.data_dict['file']]]# if self._type:#     poi_distance = round(pois[0].to_crs(crs_distance).distance(pois[1].to_crs(crs_distance)).loc[0], 2)##     poiss_ind = [self.__Check(GetNodeInd(self.data_dict["kdtree"], __v)) for __v in self.data_dict['file'] if#                  self._type]# ########################################################################################################poiss_ind = [self.__Check(GetNodeInd(self.data_dict["kdtree"], __v)) for __v in self.data_dict['file'] ifself._type]if self._type:if poiss_ind[0] == poiss_ind[1]:self._msg["data"] = "起点和终点相同"else:nodeid_lineid = self.__Check(GetNodeIdLineId(poiss_ind, self.data_dict["adjacency_matrix"], self.data_dict["node_dict"],self.data_dict["node_key"]))if self._type:point_gd = SetOutFormatGD(self.data_dict['file'], nodeid_lineid, self.data_dict['node'],self.data_dict[__kself__].loc[nodeid_lineid[1]][["Name", "Shape_Leng", "geometry"]].to_dict())self._msg["data"] = json.dumps(point_gd)return self._msgdef Main(data_dict):return AnalysisPath(data_dict).Run()if __name__ == '__main__':import numpy as npfrom cartopy import crs as ccrsimport matplotlib.pyplot as pltax = plt.axes(projection=ccrs.PlateCarree(), aspect='auto')import time, datetime__start_time = time.time()print('开始处理:', time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))import geopandas as gpdfrom scipy.spatial import KDTreepath_base = r"C:\myprojects\py_projects\get_polygon"data_dict = dict()nodes = set()data_dict[__kself__] = gpd.read_file(path_base + __keyself__[__kself__])for id in range(len(data_dict[__kself__])):points = geommapping(data_dict[__kself__]["geometry"][id])["coordinates"]##################################################################################### 获取所有点--生成前期基础数据很慢,需要优化速度# for v in points:#     nodes.append([v, data_dict[__kself__]["id"][id]])##################################################################################### 起点、中点、终点nodes.add((points[0], data_dict[__kself__]["id"][id]))# nodes.add((points[int(len(points)/2)], data_dict[__kself__]["id"][id]))nodes.add((points[-1], data_dict[__kself__]["id"][id]))data_dict[__kself__].plot(ax=ax)node_dict = {}tmp_xy = []node = []# 点关联到线,字典--key:点id,value:线idfor __i, __v in enumerate(nodes):# 过滤重复点--根据线共用点情况,多份存储if __v[0] in tmp_xy:node_dict[tmp_xy.index(__v[0])].append(__v[1])else:node_dict[__i] = [__v[1]]node.append(__v[0])tmp_xy.append(__v[0])else:del tmp_xynode_key = list(node_dict.keys())data_dict["kdtree"] = KDTree(node)data_dict["node"] = nodedata_dict["node_dict"] = node_dictdata_dict["node_key"] = node_key# 点连通性关系存储--邻接矩阵adjacency_matrix = np.zeros(shape=(len(node), len(node)), dtype=int) - 1for i in range(len(node_key)):for j in range(len(node_key)):if i == j:adjacency_matrix[i][j] = 0else:for __vj in node_dict[node_key[j]]:if __vj in node_dict[node_key[i]]:adjacency_matrix[i][j] = __vj + 1####################################################################################### 当前算法未用到距离# adjacency_matrix[i][j] = data_dict[__kself__].loc[__vj]["Shape_Leng"]######################################################################################else:data_dict["adjacency_matrix"] = adjacency_matrixdata_dict['file'] = [(104.907, 33.408), (104.916, 33.398)]# data_dict['file'] = [(104.028, 34.1034), (104.05, 34.1)]# data_dict['file'] = [(105.115, 32.6145), (105.2, 32.6306)]# data_dict['file'] = [(104.919, 33.394), (104.921, 33.391)]tmp = Main(data_dict)print(tmp)print('本次耗时:', datetime.timedelta(seconds=time.time() - __start_time), '\n')

2.c

待补充...

最短路径分析+路书(详细导航信息)相关推荐

  1. 基于百度地图和百度路书的行车轨迹回放(含途经点的多次导航)

    目录 先来看看我做了个啥 我为什么要这件事 我用到的工具 正式开始 创建一张空地图 设置我的起点.终点.途经点 为上面几个关键点打上标签 绘制折线 绘制折线的方法 第一个难点 加一辆小车在路上跑 添加 ...

  2. PostGIS 结合Openlayers以及Geoserver实现最短路径分析(二)

    前文讲述了怎么用ArcMap制作了测试数据,并导入了PostGIS,接下来我们需要结合PgRouting插件,对入库的数据再进行一下处理. 1.在pgAdmin中,执行下面的sql语句 --添加起点字 ...

  3. 百度地图轨迹回放,自定义路书,边走边画线

    转自:https://www.cnblogs.com/syj2016/p/5685294.html 百度地图轨迹回放,自定义路书,边走边画线 在原有的百度路书的基础上,做了修改,使其能实现边走边画线的 ...

  4. 百度地图 路书动态加载规划

    <html lang="en"> <head><meta charset="utf-8"/><title>路书& ...

  5. ArcMap最短路径分析和网络数据集的构建

    打断相交点 1.单击[编辑器]工具条上的编辑工具. 2.选择要在交叉点处进行分割的线要素. 3.单击[高级编辑]工具条上的打断相交线工具. 4.默认或可输入拓扑容差. 5.单击确定. 结果:所选线在相 ...

  6. 百度路书实现车辆轨迹动态回放功能-javascrpt版

    基于百度路书js实现车辆轨迹回放功能:接到一个新需求,实现车辆历史轨迹回放功能,之前没有做过,根据网上各种文章走了一些坑,基本上都是半成品,最后还是看百度地图原生api完成开发,现在把最终结果分享给大 ...

  7. vue.js BMap 与BMapLib.lushu 的配置与百度路书,结合项目后台的实例展示

    @[vue.js BMap 与BMapLib.lushu 的配置与百度路书,结合项目的实例展示] 上一章实现了百度轨迹的展现.今天写一个百度路书结合项目功能的实现. (实例很全面,认真相互探讨学习) ...

  8. 百度路书 信息显示_学会用地图制作路书,分分钟从小白变成自驾游达人

    原创文章,欢迎点评! 很多想要开车自驾游的朋友,由于自己不会做行程规划和安排,或总是感觉自己做的行程规划.安排不是很精准,不能很清晰的规划出自己每天该走多远的路?途中在景点游玩的时间应该是多少?什么时 ...

  9. postgis+geoserver+openlayers最短路径分析-学习记录bug

    学习postgis+geoserver+openlayers最短路径分析,记录遇到的奇奇怪怪的问题. 主要参考: https://www.cnblogs.com/giser-s/p/11599562. ...

最新文章

  1. 安装win7时,无法创建新的分区系统和无法定位现有分区系统
  2. c语言中读取内存的文件,c++从内存中读取文件内容,内容写到内存 实现文件的内存共享代码实例...
  3. 程序显示文本框_【教程】TestComplete测试桌面应用程序教程(二)
  4. java分布式对象RMI应用测试用例
  5. Halcon算子学习:sample_object_model_3d
  6. 银行大数据风控平台的建设要点与应用
  7. python编译反编译,你不知道的心机与陷阱
  8. Spring:aspectj-autoproxy 简介
  9. ACCESS使用VBA编辑器,ACCESS崩溃后的处理
  10. 华为云的Kubernetes实践之路
  11. 信息隐藏基础算法——LSB算法(python实现)
  12. ecshop其他页面判断是智能手机访问也跳转到ECTouch对应手机版页面[有修正]
  13. 火车头采集ajax网址的技巧,使用post方法获得采集网址
  14. 子比Zibll主题V6.3最新亲测免授权+可用版
  15. 百度地图逆地址解析,经纬度解析
  16. android 设置app 默认语言为 简体中文
  17. 基本算术运算优先级(高到低)
  18. 关于mysql中5位数字转化为日期格式的问题
  19. 【计算机毕业设计】基于微信小程序的师生答疑平台的设计与实现
  20. 【PADS9.5】PADS Logic 绘制原理图

热门文章

  1. 自动爬取ZiMuZu的内容发布到Wordpress
  2. WIN2000终端网络简介(转)
  3. 自动化助手的添加(红字公告的逆向分析C++实现函数调用以及菜单呼出)
  4. 数据挖掘笔记2017年3月1日-
  5. JavaScript压缩base64图片
  6. 将彩色和深度图转成点云图
  7. T420win7破解3G内存限制
  8. 【从零开始学习人工智能】人工智能简介 - 07机器学习
  9. android模拟器的优缺点,使用模拟器试玩软件的优点和缺点分别有哪些?
  10. 自学c语言多久能赚钱,我这样学C语言,一个月赚了2000元?