北京地铁线路规划系统——总结
目录
项目概况Github项目源代码地址:https://github.com/NewWesternCEO/beijing_subway/ 该项目在Python3.6环境下开发
数据流分析由于该工程所需要处理的数据较少,且数据处理过程为实时处理,因此不采用数据库进行存储。 文件结构与存储结构文件结构└── SubwayApp 存储结构在对线路的观察中发现北京市地铁线路的命名并不完全按数字来进行,存在特有的命名,导致不适宜直接在程序中进行处理。 因此首先对各条线路进行编码,将编码后的线路信息存放在names.txt文件中。编码后的结果为 1 地铁一号线 2 地铁二号线 3 地铁八通线 ... 17 地铁昌平线 18 地铁亦庄线 19 地铁燕房线 20 西郊线 21 S1线 22 机场线
苹果园 1 古城 1 八角游乐园 1 ... 2号航站楼 22 三元桥 22
业务逻辑实现(subwayFunction.py)全局声明 import numpy as np ERROR = -1 inf = 1e+8 数据预处理
具体实现: '''读取地铁站点信息''' def readData(path): file = open(path,'r',encoding='GB2312') N = 0 lineNum = [] lineDict = {} nodes = [] collected = [] for each in file: # print(each) node,line = each.split(' ') if not node in nodes: N += 1 nodes.append(node) collected.append(False) # 将线路分门别类 line = eval(line) if not line in lineNum: lineDict[line] = [] lineNum.append(line) lineDict[line].append(node) print('n共有 %d 个站点' % N) file.close() return N,nodes,collected,lineNum,lineDict readNames() def readNames(path): file = open(path,encoding='GB2312') names = {} for each in file: line,name = each.split(' ') name = name.replace('n','') names[eval(line)] = name return names initGraph() '''初始化''' def initGraph(path,N,nodes): graph = np.ones([N,N]) * inf #不可达 preIdx = 0 #Idx表示结点编号 preLine = ERROR file = open(path,encoding='GB2312') for each in file: node,line = each.split(' ') if preLine == ERROR: preLine = eval(line) curIdx = nodes.index(node) if curIdx != preIdx and preLine == eval(line): graph[preIdx][curIdx] = graph[curIdx][preIdx] = 1 preIdx = curIdx preLine = eval(line) return graph dijkstra算法典型的dijkstra算法实现,包含 具体实现: '''Dijkstra算法''' def findNextMin(graph,dist,N): minNode,minDist = ERROR,inf for i in range(0,N): if dist[i] < minDist and collected[i] == False: minDist = dist[i] minNode = i if minDist < inf: return minNode else: return ERROR def Dijkstra(nodes,startNode,graph,lineDict): startIdx = nodes.index(startNode) #endIdx = nodes.index(endNode) collected[startIdx] = True dist = np.ones(N) * inf path = np.ones(N) for i in range(0,N): dist[i] = graph[startIdx][i] if dist[i] < inf: path[i] = startIdx else: path[i] = ERROR while True: nextNodeIdx = findNextMin(graph=graph,dist=dist,collected=collected,N=N) lines1 = getLine(nextNodeIdx,lineDict) if nextNodeIdx == ERROR: break collected[nextNodeIdx] = True for i in range(0,N): if collected[i] == False and graph[nextNodeIdx][i] < inf: if dist[nextNodeIdx] + graph[nextNodeIdx][i] < dist[i]: dist[i] = dist[nextNodeIdx] + graph[nextNodeIdx][i] path[i] = nextNodeIdx return dist,path 输出文件输出文件通过
'''获取站点所在的线路号''' def getLine(node,lineDict): lines = [] for key in lineDict.keys(): if node in lineDict[key]: lines.append(key) return lines '''整理结果并输出文件''' def output(nodes,startLine,endNode,path,lineDict,names): listOut = [] outputPath = r'./routine.txt' outputFile = open(outputPath,'w') tracePath = [] tracePath.append(nodes.index(endNode)) pos = int(path[nodes.index(endNode)]) while pos != ERROR: tracePath.append(pos) pos = int(path[pos]) tracePath.reverse() curLine = [] # curLine.append(eval(startLine) curLine.append(startLine) temp = startLine first = True print(len(tracePath)) listOut.append(str(len(tracePath))) outputFile.write(str(len(tracePath))) outputFile.write('rn') for each in tracePath: if first == False: lines = getLine(nodes[each],lineDict) if len(curLine) == 1: if len(lines) == 1: if lines[0] != curLine[0]: curLine[0] = lines[0] name = names[curLine[0]] print(name) listOut.append(name) outputFile.write(name) outputFile.write('rn') temp = curLine[0] elif len(lines) >= 2: curLine = lines elif len(curLine) >= 2: if len(lines) == 1: if lines[0] != temp: curLine = [] curLine.append(lines[0]) name = names[curLine[0]] print(name) listOut.append(name) outputFile.write(name) outputFile.write('rn') temp = curLine[0] elif len(lines) >= 2: newLine = list(set(curLine).intersection(lines))[0] if newLine != temp: curLine = [] curLine.append(newLine) name = names[curLine[0]] print(name) listOut.append(name) outputFile.write(name) outputFile.write('rn') temp = curLine[0] else: curLine = lines print(nodes[each]) listOut.append(nodes[each]) outputFile.write(nodes[each]) outputFile.write('rn') first = False outputFile.close() return listOut 异常处理用户给与的输入信息在web的限制下已经变得非常有限。 因此可以在调用业务函数之前通过判断来处理异常,在通过所有检查的情况下才将请求交给后台处理。 if startNode == endNode: flash('出发站与终点站不能相同') startNode = "error" elif startLine == '' or not eval(startLine) in lineNum: flash("请选择正确的出发线路") startNode = "error" elif endLine == '' or not eval(endLine) in lineNum: flash("请选择正确的终点线路") startNode = "error" elif not startNode in lineDict[eval(startLine)]: flash("请选择正确的出发站") startNode = "error" elif not endNode in lineDict[eval(endLine)]: flash("请选择正确的终点站") startNode = "error" else: return redirect(url_for('loadResult')) 在用户尝试提交非法的请求时,会产生如下的提示: 前端搭建通过Flask与Bootstrap结合的方式搭建web页面。
<script type="text/javascript"> //1、用户选哪条线 var startLine = document.getElementById("startLine"); var endLine = document.getElementById("endLine"); //2、定位到对应的线路集合 var startNode = document.getElementById("startNode"); var endNode = document.getElementById("endNode"); //动态-改进 var nodes = {{ lineDict|tojson }} $(".lineDict").html(nodes) //3、动态的添加标签 function showStart() { startNode.innerHTML = "--选择一个起始站--"; var line = startLine.value for (var i in nodes[line]) { startNode.innerHTML += "<option>" + nodes[line][i] + "</option>"; } } function showEnd() { endNode.innerHTML = "--选择一个起始站--"; var line = endLine.value for (var i in nodes[line]) { endNode.innerHTML += "<option>" + nodes[line][i] + "</option>"; } } </script> 随后将页面挂载到 AWS 的 EC2 实例上。 具体的挂载方法可以参考如下两篇博客,虽然博客中使用的是阿里云的服务器,但配置思路与AWS类似。
结果呈现本地测试输入 '''sample''' startNode = '西直门' endNode = '北京南站' startLine = 13 运行结果 web端测试输入 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |