目录
1.编写目的
编写该文章的目的是在开发时需要用到自定义的路网导航,查阅高德、百度地图等相关网站后,并没有发现可自定义路网的导航,后来在Git上搜到了Graphhopper这个国外的开源软件,然后学习使用后实现了自定义路网导航的功能,现在记录一下自己的实现过程,以保存开发资料,并且帮助到需要实现相关功能的朋友。
2.项目准备
2.1 openstreet账号
项目需要使用OpenStreet网站专属的OSM文件格式,所以需要在https://www.openstreetmap.org/进行在线的绘制(并没有找到好用的文件转换工具,并且国内相关教程也很少),这里需要自己在这个网站注册一个账号并登录。
2.2 绘制路网数据并导出OSM路网文件
登录后点击编辑按钮进入编辑界面,在当前界面中可以绘制线并完成要素类型选择,如选择小道(这将仅在步行导航时才会生效)、小型等级外道路(车、步行、自行车),不同道路类型使用不同交通工具。
绘制完成后点击右上角保存按钮,完成自定义路径的保存。
然后输入更新提示信息完成数据的保存。
在主界面点击导出按钮进入导出页面,输入经纬度坐标完成目标区域的选择或选择”手动选择目标区域”来框选目标区域(注:这里最多导出50000节点),点击导出按钮完成导出操作,导出为osm文件。
2.3 Jar包准备
这里可以去gitHub自己下载Releases · graphhopper/graphhopper · GitHub,也可以使用我使用的Jar包。在置顶资源中graphhopper-web-9.0.jar
3.Springboot项目搭建
3.1 配置jar包
将jar包复制到项目路径中,这里复制到项目的lib文件夹下,并配置pom文本地路径,配置如下:
<dependency>
<groupId>com.graphhopper</groupId>
<artifactId>graphhopper-web</artifactId>
<scope>system</scope>
<version>9.0</version>
<systemPath>${project.basedir}/lib/graphhopper-web-9.0.jar</systemPath>
</dependency>
3.2 实现graphhopper配置类
@Configuration
public class GraphhopperConfig {
@Bean
public GraphHopper graphHopper(){
//这里定义步行导航和汽车导航的文件并指定交通工具
List<Profile> profile=new ArrayList<Profile>();
profile.add(new Profile("foot").setVehicle("foot"));
profile.add(new Profile("car").setVehicle("car"));
GraphHopper graphHopper=new GraphHopper();
//这里配置导出的osm文件
graphHopper.setOSMFile("osm文件路径");
//这里配置程序启动时预处理节点文件存放位置
graphHopper.setGraphHopperLocation("预处理节点文件存放位置");
//使用配置文件
graphHopper.setProfiles(profile);
graphHopper.importOrLoad();
return graphHopper;
}
}
首先置顶要使用的交通工具,有三种交通工具为步行(foot)、汽车(car)、自行车(bike),这里使用foot和car进行测试.然后是配置osm文件路径,这里是导出的osm文件的位置.预处理存放位置为一个空文件夹,将会在程序启动时处理osm文件并缓存节点文件到该文件夹下,使用配置文件导入或者加载。(注:这里程序启动一次后除非删除缓存节点文件中的文件,否则节点文件不会更新,即更新路网数据时需先删除缓存的节点文件)。
3.3 实现访问接口
@GetMapping("/navigate")
public String navigate(@RequestParam("start") String start, @RequestParam("end") String end,@RequestParam("vehicle") String vehicle) {
GHRequest request = new GHRequest()
.setAlgorithm(Parameters.Algorithms.DIJKSTRA_BI) // 设置路径搜索算法
.setProfile(vehicle)
.addPoint(fromString(start))
.addPoint(fromString(end));
GHResponse response = graphHopper.route(request); // 计算路径
if (response.hasErrors()) {
return "Error: " + response.getErrors().get(0).getMessage();
} else {
System.err.println("距离:"+response.getBest().getDistance());
System.err.println("时间:"+response.getBest().getTime());
return convertToGeoJson(response.getBest().getPoints());
}
}
//这里将,分割经纬度转换为GHPoint类
private GHPoint fromString(String str) {
String[] parts = str.split(",");
return new GHPoint(Double.parseDouble(parts[0]), Double.parseDouble(parts[1]));
}
//这里将路径转换为GeoJson
private String convertToGeoJson(PointList path) {
JSONObject featureCollection = new JSONObject();
featureCollection.put("type", "FeatureCollection");
JSONArray features = new JSONArray();
JSONObject feature = new JSONObject();
feature.put("type", "Feature");
Map<String,Object> properties=new HashMap<>();
properties.put("Shape_Length",0.003024242688834029);
feature.put("properties", properties);
JSONObject geometry = new JSONObject();
geometry.put("type", "LineString");
JSONArray coordinates = new JSONArray();
for (GHPoint point : path) {
JSONArray coordinate = new JSONArray();
coordinate.add(point.lon);
coordinate.add(point.lat);
coordinates.add(coordinate);
}
geometry.put("coordinates", coordinates);
feature.put("geometry", geometry);
features.add(feature);
featureCollection.put("features", features);
return featureCollection.toString();
}
先构建GHRequest,在该对象中传入起始点经纬度、结束点经纬度、设置使用的vehice,即选择不同的配置文件,调用route方法获取路径响应,并通过getBest()方法获取最短路径.同时在该响应对象中还可获取如路径距离、路径时间、行走方向等信息。下面的两个方法为辅助方法分别是转换为GHPoint和转换为GeoJson方法。
4.功能测试
将结果进行可视化,这里使用在线网站:https://geojson.io/