参考了许多文章,包括b站up主老程序员老关、csdn:Liu Zhian还有很多边边角角的代码、文章,孩子为写毕业论文踩碎了心。
文章目录
- 1.将osm文件有效数据提取到csv
- 2.将提取出的数据转换为network文件所需数据
- 3.将数据转化为network.xml文件
- 4终于搞完这个17w行的数据了呜呜呜 喜大普奔!!!
1.将osm文件有效数据提取到csv
osm文件有两大部分,分开操作,将其分为两个文件
分成两个文件:
下面是两个文件
<?xml version='1.0' encoding='UTF-8'?>
<nodes>
<node id='-101752' lat='40.6592449' lon='109.7662487' />
<node id='-101753' lat='40.6587893' lon='109.7727179' />
<node id='-101755' lat='40.6585103' lon='109.7767641' />
<node id='-101756' lat='40.6581603' lon='109.7838497' />
<node id='-101757' lat='40.6581441' lon='109.7841119' />
<node id='-101758' lat='40.6459848' lon='109.886676' />
<node id='-101759' lat='40.6456042' lon='109.8865427' />
<node id='-101760' lat='40.6426309' lon='109.8838162' />
<node id='-101761' lat='40.6425291' lon='109.8836902' />
<node id='-101762' lat='40.6424558' lon='109.8835789' />
<node id='-101763' lat='40.6424222' lon='109.8833187' />
<node id='-101764' lat='40.6426996' lon='109.8780347' />
</nodes>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
<?xml version='1.0' encoding='UTF-8'?>
<links>
<way id='-101783' action='modify'>
<nd ref='-101752' />
<nd ref='-101753' />
<nd ref='-101755' />
<nd ref='-101756' />
<nd ref='-101757' />
<tag k='highway' v='primary' />
<tag k='osm_id' v='13456925' />
<tag k='z_order' v='7' />
</way>
<way id='-101785' action='modify'>
<nd ref='-101758' />
<nd ref='-101759' />
<nd ref='-101760' />
<nd ref='-101761' />
<nd ref='-101762' />
<nd ref='-101763' />
<nd ref='-101764' />
<nd ref='-101767' />
<nd ref='-101768' />
<nd ref='-101769' />
<nd ref='-101771' />
<nd ref='-101772' />
<nd ref='-101773' />
<nd ref='-101774' />
<nd ref='-101775' />
<nd ref='-101777' />
<nd ref='-101778' />
<tag k='highway' v='primary' />
<tag k='osm_id' v='13457299' />
<tag k='z_order' v='7' />
</way>
</links>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
下面是python处理代码:
#生成nodes部分
import xml.etree.ElementTree as ET
tree = ET.parse('nodes.xml')#输入xml文档树
print(type(tree))#xml.etree.ElementTree.ElementTree
root = tree.getroot()#root是根元素
print(type(root))#xml.etree.ElementTree.ElementTree
print(root.tag) #notes
with open("nodes.txt","w")as f:
for index,child,in enumerate(root):
f.write('{0}'.format(child.attrib))
f.write('\n')
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
#生成links部分
from xml.dom.minidom import parse
def readXML():
domTree = parse("./links.xml")
# 文档根元素
rootNode = domTree.documentElement
print(rootNode.nodeName)
# 所有顾客
links = rootNode.getElementsByTagName("way")
with open("links.txt","w")as f:
f.write("****所有way信息****")
f.write('\n')
for way in links:
ways = way.getElementsByTagName("nd")
if way.hasAttribute("id"):
f.write('\n')
f.write('id:{0}'.format(way.getAttribute("id")))
# name 元素
for nd in ways:
if nd.hasAttribute("ref"):
f.write('ref:{0}'.format(nd.getAttribute("ref")))
if __name__ == '__main__':
readXML()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
将生成的结果处理一下,去掉无用字符,就得到数据啦,再把数据做成逗号分隔格式,就可存入csv保存了。
2.将提取出的数据转换为network文件所需数据
提取出的数据中,nodes部分需要将地理坐标系转换为投影坐标系;links部分需要将站点编号与地理坐标对应,从而求出每条路径长度。
- nodes与links的目标格式:
- nodes部分坐标系转换
直接暴力套用MATLAB代码:(生成的XY就是平面坐标系矩阵)
%% 转化坐标系,需要参数为点的经纬度矩阵xy
%MATLAB程序实现经纬度转换成平面尔坐标:
M_PI=3.14159265358979323846;
L = 6381372 * M_PI * 2; %地球周长
W = L; % 平面展开后,x轴等于周长
H = L / 2; % y轴约等于周长一半
mill = 2.3; % 米勒投影中的一个常数,范围大约在正负2.3之间
n=size(xy,1);
%lon=120.7015202;%经度
%lat=36.37423;%纬度
new_xy=[];
XY=[0,0];
for i =1:n
lon=xy(i,1);
lat=xy(i,2);
x = lon * M_PI / 180; % 将经度从度数转换为弧度
y = lat * M_PI / 180; %将纬度从度数转换为弧度
y1 = 1.25 * log(tan(0.25 * M_PI + 0.4 * y)); % 米勒投影的转换
% 弧度转为实际距离
dikaerX = (W / 2) + (W / (2 * M_PI)) * x ; %笛卡尔坐标x
dikaerY = (H / 2) - (H / (2 * mill)) * y1 ;%笛卡尔坐标y
new_xy(i,1)=dikaerX;
new_xy(i,2)=dikaerY;
XY=[XY;new_xy(i,1),new_xy(i,2)];
end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- link部分的from-to数据处理(目的:生成每个路段的起讫点序号)
from xml.etree.ElementTree import Element, ElementTree, tostring,SubElement
from itertools import islice #方便csv文件去表头工作
import argparse
import os
import csv
with open('links.txt','r')as f:
reader = csv.reader(f)
#line_count=0
count=len(open(r"links.txt",'rU').readlines())#获取行数
print("行数:",count)
rows=[row for row in reader]
print(rows[0])
print(len(rows[0]))
print(type(rows[0]))
print(rows[0][1])
with open ("links2.txt","w")as f:
for i in range(count):
length=len(rows[i])-2
for j in range(length):
f.write('{0}'.format(rows[i][j+1])+','+'{0}'.format(rows[i][j+2]))
f.write('\n')
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- links部分的length距离转化(目的:求出每个路段的距离)
links现有数据为每段路的起始点编号,让它与nodes数据中的地理位置对应,计算出每个路段的长度就OK啦,这里用MATLAB计算。(对于比较精细的osm地图误差小)
代码需要的数据:xy
代码需要的数据:links2
%% 输出起讫点(from-to)的坐标
clear
load("data.mat")
[n,~]=size(links2);
for i=1:n
from=links2(i,1);%起点编号
to=links2(i,2);%讫点编号
[a,b]=find(xy(:,1)==from);x_from=xy(a,3);%x_from是起点横坐标
[a,b]=find(xy(:,1)==from);y_from=xy(a,2);%x_from是起点横坐标
[a,b]=find(xy(:,1)==to);x_to=xy(a,3);%x_from是起点横坐标
[a,b]=find(xy(:,1)==to);y_to=xy(a,2);%x_from是起点横坐标
links2(i,3)=x_from;links2(i,4)=y_from;links2(i,5)=x_to;links2(i,6)=y_to;
%将起讫点横纵坐标放入线段起讫点编号的后面。
end
save('data.mat','links2','xy');
%% 计算距离
clear
load("data.mat")
[n,~]=size(links2);
for i=1:n
links2(i,7)=((links2(i,3)-links2(i,5))^2+(links2(i,4)-links2(i,6))^2)^0.5;
end
save('finish','links2');
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
保存到工作区的“finish.mat”就是最终数据了,第七列为距离。
最后是这样的
到此为止,所有network文件需要的数据已经准备好啦!
3.将数据转化为network.xml文件
剩下的部分就简单多了,依旧是nodes部分与links部分分开操作。思路是用python把每行数据前后都写上字符串输出。
- nodes部分python代码
from itertools import islice #方便csv文件去表头工作
import argparse
import os
import csv
with open('nodes_finish.txt','r')as f:
reader = csv.reader(f)
count=len(open(r"nodes_finish.txt",'rU').readlines())#获取行数
print("行数:",count)
rows=[row for row in reader]
print(rows[0])
with open ("network_nodes.txt","w")as f:
for i in range(count):
f.write('<node id=\"'+'{0}'.format(rows[i][0])+'\"'+' '+'x=\"'+'{0}'.format(rows[i][2])+'\"'+' '+'y=\"'+'{0}'.format(rows[i][1])+'\"'+' />')
f.write('\n')
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
生成文件改成xml格式如下图:
- links部分python代码
from itertools import islice #方便csv文件去表头工作
import argparse
import os
import csv
with open('links_finish.txt','r')as f:
reader = csv.reader(f)
count=len(open(r"links_finish.txt",'rU').readlines())#获取行数
print("行数:",count)
rows=[row for row in reader]
print(rows[0])
with open ("network_links.txt","w")as f:
for i in range(count):
f.write('<link id=\"'+'{0}'.format(i)+'\"'+' '+'from=\"'+'{0}'.format(rows[i][0])+'\"'+' '+'to=\"'+'{0}'.format(rows[i][1])+'\"')
f.write(' '+'length=\"'+'{0}'.format(rows[i][6])+'" capacity="1000" freespeed="100" modes="car" permlanes="1" '+'/>')
f.write('\n')
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
将生成文件格式改为xml(如下图),就Ok啦
- nodes与links二者合并!
当然是复制粘贴,然后改缩进啦!
4终于搞完这个17w行的数据了呜呜呜 喜大普奔!!!
*交通仿真老师带我们领进了matsim的门,但是matsim文件用的是Java语言,越看头越大!都说python很简单,灵(tu)光(ran)一(nao)闪(can):那我就用python搞这个呗…结果就入了python+matsim的破坑,而且坑里就我一人…在摸索中爬行,如有纰漏希望好心人指出,也希望能给其他不小心入错坑的惨宝们参考。鞠躬.jpg