- 1.前言
- 2.数据接入前置必须条件
- 3.OSM数据示例
- 4.SHP->OSM
- Copyright (c) 2006 Gabriel Ebner ge@gabrielebner.at
- updated in 2008 by Tobias Wendorff tobias.wendorff@uni-dortmund.de
- HTML-Entities based on ideas of Hermann Schwärzler
- Gauß-Krüger implementation based on gauss.pl by Andreas Achtzehn
- version 1.3 (17. September 2008)
- BEGIN { our %default_tags = ( natural => ‘water’, source => ‘SWDB’ ); }
- JOSM插件方法
- 5.导入后的数据接入Graphhopper
- 6.Shp数据介绍
1.前言
众所周知,Graphhopper可以通过OSM数据或GTFS数据提供导航服务,对于其他的数据,Graphhopper是不支持的。
但是很多时候,用户想接入自己的数据进行导航,此时就需要进行一个数据的转化,才可以将用户数据接入Graphhopper来提供导航服务
而用户最常用的数据,就是shp类型的数据,接下来,我们通过shp类型的数据为例,来讲解如何将shp类型数据接入Graphhopper,大致可分为以下步骤
- 了解数据接入有哪些前置必备条件
- 了解OSM数据的格式以及示例
- 了解如何将shp数据转换为osm数据
- 测试转换后的osm数据准确性
- 将转换后的osm数据接入Graphhopper进行测试
-
2.数据接入前置必须条件
数据坐标系要求
OSM可视化软件下载
下载
使用的软件名称为Josm(Java OpenStreetMap),是一款由Java编写,专门进行OSM编辑,查看,下载的软件
下载地址:https://josm.openstreetmap.de/
点击下图所示,即可下载
安装
下载为.exe文件,直接点击运行即可。需要注意的是,,JOSM无法选择安装地址,默认安装到C盘!!!!这一点属实有点讨厌
运行
安装完成后,运行即可。如下图,点击文件->打开即可打开OSM文件
3.OSM数据示例
包含四个部分,header标签,node标签,way标签,relation标签
- node标签,way标签,relation标签都具有id,visible(可见性),user(作者),lon,lat等基本属性
- 可以通过tag标签对node、way、relation标签的属性进行属性描述
<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="CGImap 0.8.8 (3727084 spike-07.openstreetmap.org)" copyright="OpenStreetMap and contributors" attribution="http://www.openstreetmap.org/copyright" license="http://opendatacommons.org/licenses/odbl/1-0/">
<bounds minlat="25.0553000" minlon="121.5731000" maxlat="25.0634000" maxlon="121.5836000"/>
<node id="661021630" visible="true" version="5" changeset="42553462" timestamp="2016-09-30T22:10:32Z" user="calfarome" uid="2511706" lat="25.0633286" lon="121.5806923">
<tag k="highway" v="traffic_signals"/>
</node>
<node id="1838345068" visible="true" version="7" changeset="94533002" timestamp="2020-11-21T06:33:37Z" user="Supaplex" uid="274857" lat="25.0642896" lon="121.5758457">
<tag k="amenity" v="atm"/>
<tag k="operator" v="華南銀行"/>
<tag k="operator:en" v="Hua Nan"/>
</node>
<node id="6336435728" visible="true" version="4" changeset="74199387" timestamp="2019-09-07T07:21:02Z" user="Supaplex" uid="274857" lat="25.0567279" lon="121.5817995">
<tag k="description" v="台北市內湖區週美里"/>
<tag k="emergency" v="fire_hydrant"/>
<tag k="fire_hydrant:type" v="underground"/>
<tag k="fire_hydrant:type:zh" v="地下式消防栓"/>
<tag k="ref:DGNID" v="4747"/>
<tag k="ref:UFID" v="3085"/>
<tag k="source" v="臺北自來水事業處"/>
</node>
<way id="676750092" visible="true" version="1" changeset="68129856" timestamp="2019-03-14T09:31:43Z" user="xu3louisyi" uid="4819877">
<nd ref="6337341000"/>
<nd ref="6337340944"/>
<nd ref="6337340943"/>
<nd ref="6337340998"/>
<nd ref="6337341000"/>
<tag k="building:levels" v="4"/>
<tag k="building:min_level" v="3"/>
<tag k="building:part" v="yes"/>
</way>
<relation id="13235028" visible="true" version="2" changeset="114127108" timestamp="2021-11-23T07:31:53Z" user="stevennero" uid="14243003">
<member type="relation" ref="13235026" role=""/>
<member type="relation" ref="13235027" role=""/>
<tag k="name" v="臺北市 南京幹線 南港高工—圓環"/>
<tag k="name:en" v="Taipei City Nanjing Metro Bus Nangang Vocational High School-Taipei Circle"/>
<tag k="name:zh" v="臺北市 南京幹線 南港高工—圓環"/>
<tag k="network" v="臺北市市區公車"/>
<tag k="network:en" v="Taipei Joint Bus System"/>
<tag k="network:nan" v="Tâi-pak-chhī Chhī-khu Kong-chhia"/>
<tag k="network:nan-HJ" v="臺北市市區公車"/>
<tag k="network:nan-POJ" v="Tâi-pak-chhī Chhī-khu Kong-chhia"/>
<tag k="network:nan-TL" v="Tâi-pak-tshiī Tshī-khu Kong-tshia"/>
<tag k="network:wikidata" v="Q5972821"/>
<tag k="network:wikipedia" v="zh:臺北市市區公車"/>
<tag k="network:zh" v="臺北市市區公車"/>
<tag k="old_ref" v="棕7"/>
<tag k="old_ref:en" v="BR7"/>
<tag k="opening_hours" v="Mo-Su 05:30-23:30"/>
<tag k="operator" v="首都客運"/>
<tag k="operator:en" v="Capital Bus"/>
<tag k="ref" v="南京幹線"/>
<tag k="ref:en" v="Nanjing Metro Bus"/>
<tag k="route_master" v="bus"/>
<tag k="type" v="route_master"/>
</relation>
</osm>
4.SHP->OSM
SHP文件转OSM文件目前网上推荐了2种方法,各有利弊,接下来开始逐一说明Perl脚本方法
创建Perl文件
创建名为shp2osm的pl文件。文件内容如下 ```perlCopyright (c) 2006 Gabriel Ebner ge@gabrielebner.at
updated in 2008 by Tobias Wendorff tobias.wendorff@uni-dortmund.de
HTML-Entities based on ideas of Hermann Schwärzler
Gauß-Krüger implementation based on gauss.pl by Andreas Achtzehn
version 1.3 (17. September 2008)
use Geo::ShapeFile; use HTML::Entities qw(encode_entities_numeric); use Math::Trig;
if(@ARGV == 0) { print “usage:\n”; print “with transformation from GK to WGS84: ‘shp2osm.pl shapefile GK’\n”; print “without transformation: ‘shp2osm.pl shapefile’”; exit; }
print <<’END’; <?xml version=’1.0’?>
BEGIN { our %default_tags = ( natural => ‘water’, source => ‘SWDB’ ); }
BEGIN { our %default_tags = ( ); }
my $file = @ARGV[0]; $file =~ s/.shp$//; my $shpf = Geo::ShapeFile->new($file); proc_shpf($shpf);
{ BEGIN { our $i = -1; }
sub tags_out {
my ($tags) = @_;
my %tags = $tags ? %$tags : ();
#$tags{'created_by'} ||= 'shp2osm.pl';
delete $tags{'_deleted'} unless $tags{'_deleted'};
while ( my ( $k, $v ) = each %tags ) {
my $key = encode_entities_numeric($k);
my $val = encode_entities_numeric($v);
print ' <tag k="'. $key .'" v="'. $val ."\"/>\n" if $val;
}
}
sub node_out {
my ( $lon, $lat, $tags ) = @_;
my $id = $i--;
if(@ARGV[1] eq 'GK') {
my ($wgs84lon, $wgs84lat) = gk2geo($lon, $lat);
print " <node id='$id' visible='true' lat='$wgs84lat' lon='$wgs84lon' />\n";
} else {
print " <node id='$id' visible='true' lat='$lat' lon='$lon' />\n";
}
$id;
}
sub seg_out {
my $id = $i+1;
$id;
}
sub way_out {
my ( $segs, $tags ) = @_;
my $id = $i--;
print " <way id='$id' visible='true'>\n";
print " <nd ref='$_' />\n" for @$segs;
tags_out $tags;
print " </way>\n";
$id;
}
}
print <<’END’; END
sub polylineout { my ( $pts, $tags, $connect_last_seg ) = @;
my ( $first_node, $last_node, @segs );
for my $pt (@$pts) {
my $node = node_out @$pt;
push @segs, seg_out $last_node, $node;
$last_node = $node;
$first_node ||= $last_node;
}
push @segs, seg_out $last_node, $first_node
if $first_node && $connect_last_seg;
way_out \@segs, $tags;
}
sub procobj { my ( $shp, $dbf, $type ) = @; my $tags = { %defaulttags, %$dbf }; my $is_polygon = $type % 10 == 5; for ( 1 .. $shp->num_parts ) { polyline_out [ map( [ $->X(), $->Y() ], $shp->get_part($) ) ], $tags, $is_polygon; } }
sub procshpf { my ($shpf) = @; my $type = $shpf->shapetype; for ( 1 .. $shpf->shapes() ) { my $shp = $shpf->get_shp_record($); my %dbf = $shpf->getdbf_record($); proc_obj $shp, \%dbf, $type; } }
sub gk2geo { my $sr = $[0]; my $sx = $[1];
my $bm = int($sr/1000000); my $y = $sr-($bm1000000+500000); my $si = $sx/111120.6196; my $px = $si+0.143885358sin(2$si0.017453292)+0.00021079sin(4$si0.017453292)+0.000000423sin(6$si0.017453292); my $t = (sin($px0.017453292))/(cos($px0.017453292)); my $v = sqrt(1+0.006719219cos($px0.017453292)cos($px0.017453292)); my $ys = ($y$v)/6398786.85; my $lat = $px-$ys$ys57.29577$t$v$v(0.5-$ys$ys(4.97-3$t$t)/24); my $dl = $ys57.29577/cos($px0.017453292) (1-$ys$ys/6($v$v+2$t$t-$ys$ys(0.6+1.1$t$t)(0.6+1.1$t$t))); my $lon = $bm*3+$dl;
my $potsd_a = 6377397.155; my $wgs84_a = 6378137.0; my $potsd_f = 1/299.152812838; my $wgs84_f = 1/298.257223563;
my $potsd_es = 2$potsd_f - $potsd_f$potsd_f;
my $potsd_dx = 606.0; my $potsd_dy = 23.0; my $potsd_dz = 413.0; my $pi = 3.141592654; my $latr = $lat/180$pi; my $lonr = $lon/180$pi;
my $sa = sin($latr); my $ca = cos($latr); my $so = sin($lonr); my $co = cos($lonr);
my $bda = 1-$potsd_f;
my $delta_a = $wgs84_a - $potsd_a; my $delta_f = $wgs84_f - $potsd_f;
my $rn = $potsd_a / sqrt(1-$potsd_essin($latr)sin($latr)); my $rm = $potsd_a ((1-$potsd_es)/sqrt(1-$potsd_essin($latr)sin($latr)1-$potsd_essin($latr)sin($latr)1-$potsd_essin($latr)*sin($latr)));
my $ta = (-$potsd_dx$sa$co - $potsd_dy$sa$so)+$potsd_dz$ca; my $tb = $delta_a(($rn$potsd_es$sa$ca)/$potsd_a); my $tc = $delta_f($rm/$bda+$rn$bda)$sa*$ca; my $dlat = ($ta+$tb+$tc)/$rm;
my $dlon = (-$potsd_dx$so + $potsd_dy$co)/($rn*$ca);
my $wgs84lat = ($latr + $dlat)180/$pi; my $wgs84lon = ($lonr + $dlon)180/$pi;
return( $wgs84lon, $wgs84lat); }
![image.png](https://cdn.nlark.com/yuque/0/2022/png/28218714/1663833719550-8ba4b216-ac33-4561-a42f-d9b2aa0368b8.png#clientId=u4e11a8f6-8057-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=712&id=ue568caa7&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1068&originWidth=1770&originalType=binary&ratio=1&rotation=0&showTitle=false&size=101990&status=done&style=none&taskId=u04be513a-a17b-4517-93c6-0d065369924&title=&width=1180)
<a name="IaEqh"></a>
#### 安装Perl运行环境
下载地址:[https://strawberryperl.com/](https://strawberryperl.com/),选择对应位数下载即可<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/28218714/1663833833792-fdb7cd71-9f64-4bc7-a602-9eb50715416f.png#clientId=u4e11a8f6-8057-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=916&id=u69e5f065&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1374&originWidth=2559&originalType=binary&ratio=1&rotation=0&showTitle=false&size=640859&status=done&style=none&taskId=u2108e4e2-d281-4dea-9aec-4138361a9e9&title=&width=1706)<br />下载后为msi文件,直接点击即可安装,一路next即可<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/28218714/1663833967727-ae2dc55c-d08d-48f1-95b7-869db0246a72.png#clientId=u4e11a8f6-8057-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=309&id=uf03cd490&margin=%5Bobject%20Object%5D&name=image.png&originHeight=463&originWidth=1256&originalType=binary&ratio=1&rotation=0&showTitle=false&size=44271&status=done&style=none&taskId=u27231adb-66b8-422a-a975-37d3263c5a3&title=&width=837.3333333333334)
<a name="HTXZH"></a>
#### 安装脚本运行依赖
Perl运行环境安装完成后,还需安装脚本所需依赖<br />任意目录下打开CMD命令行工具,输入如下命令
```shell
cpan Geo::ShapeFile
文件转换
- 将shp2osm.pl文件复制到shp文件目录下
- 在shp文件同目录下,打开CMD命令行
运行如下命令。其中*.shp代码目录下所有shp文件
FOR /R .\ %G IN (*.shp) DO shp2osm.pl "%~dpnG" > "%~dpnG.osm"
验证
优点
便于操作,运行命令即可,无需额外安装各种软件
-
缺点
该脚本文件内容版本较老,有可能不适配高版本OSM文件标椎
- 部分shp数据转换过程中会报错,具体原因不明
导出的文件,node节点与way节点乱序,无法接入Graphhopper
JOSM插件方法
安装opendata插件
JOSM文件原本无法打开shp文件,需额外安装opendata插件才可查看shp文件
点击编辑->首选项
- 点击插件
- 搜索opendata,点击确认即可
等下下载完成后,重启JOSM即可。(插件下载过程非常缓慢,要有点心理准备,等着就好)
打开shp文件
安装完插件后,点击文件->打开,选择shp文件即可打开(打开过程会有点慢,要等等)
转存为OSM文件
点击文件->另存为
- 修改文件名后缀为.osm,并选择保存文件OSM项即可
- 如下,OSM文件存储成功
验证
使用JOSM打开刚刚转存的文件,如下,可以看到,OSM文件转储成功
优点
可以解决Perl脚本方法报错问题,截止到目前没遇到过shp文件转换异常
缺点
-
5.导入后的数据接入Graphhopper
目前数据接入异常
第一个异常原因
导入数据所有tags皆为无效tags,导致路径数据导入时,被判定为无效,进而导致nodes数据无法获得路径关联,被判定为空点,最后出现异常
最重要方法: OSMReader->preProcess
-
第二个异常原因
经过源码修改后,屏蔽了tags以及id相关检查,但是因为没有tags,因此无法进行权重,速度,等相关的属性关联,导致查询无返回数据
解决方法
了解osm数据的tags属性集
- 了解shp数据的属性信息
-
6.Shp数据介绍
常见的Shp文件通常包括如下5种
shp:图形格式,用于保存元素的几何实体
- shx: 图形索引文件,几何体位置索引,记录每一个几何体在shp文件之中的位置,能够加快向前或向后搜索一个几何体的效率。
- dbf: 属性数据格式,以dBase IV的数据表格式存储每个几何形状的属性数据。
- prj:用于保存地理坐标系统与投影信息,是一个存储well-known text投影描述符的文本文件
- cpg:用于描述.dbf文件的代码页,指明其使用的字符编码