目录
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/
编辑