系列文章目录
Java精准地图坐标转换 高德 百度 谷歌 腾讯 高德 批量转换工具类达到项目生产精度
文章目录
前言
最近项目有个需求,需要画出安徽省所有的服务区、收费站、桥梁、隧道等,Gis玩久了就知道了,有数据就很easy,但是可惜这个数据我们没有,买是不可能买的,那就另辟蹊径,所以我就从高德上爬了点儿(合法滴哦
),效果图如下:
一、先去高德注册个账号
已有账号的直接跳过哈
-
首先,注册账号,成为高德开放平台开发者
-
登陆之后,在进入「应用管理」 页面「创建新应用」
-
为应用添加 Key,「服务平台」一项请选择「 Web服务」
二、通过高德POI接口抓取坐标数据
搜索POI接口文档非常的详细
搜索服务API是一类简单的HTTP接口,提供多种查询POI信息的能力,其中包括关键字搜索、周边搜索、多边形搜索、ID查询四种筛选机制。
适用场景
- 关键字搜索:通过用POI的关键字进行条件搜索,例如:肯德基、朝阳公园等;同时支持设置POI类型搜索,例如:银行
- 周边搜索:在用户传入经纬度坐标点附近,在设定的范围内,按照关键字或POI类型搜索;
- 多边形搜索:在多边形区域内进行搜索
- ID查询:通过POI ID,查询某个POI详情,建议可同输入提示API配合使用
代码示例
依赖Jar,pom.xml
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.3</version>
</dependency>
以抓取服务区为示例:
/**
* 获取兴趣点,例如交通上常用的服务区,收费站,桥梁,隧道等
*
* @param cityCode 为了您查询的精确,我们强烈建议您使用adcode。
* 安徽省 340000
* 可选值:城市中文、中文全拼、citycode、adcode
* 如:北京/beijing/010/110000
* 填入此参数后,会尽量优先返回此城市数据,但是不一定仅局限此城市结果,若仅需要某个城市数据请调用citylimit参数。
* 如:在深圳市搜*,返回北京*结果。
* @param poiType 查询POI类型,建议分类代码
* 可选值:分类代码 或 汉字(若用汉字,请严格按照附件之中的汉字填写)
* 分类代码由六位数字组成,一共分为三个部分,前两个数字代表大类;中间两个数字代表中类;最后两个数字代表小类。
* 若指定了某个大类,则所属的中类、小类都会被显示。
* 例如:010000为汽车服务(大类)
* 010100为加油站(中类)
* 010101为中国石化(小类)
* 010900为汽车租赁(中类)
* 010901为汽车租赁还车(小类)
* <p>
* **POI分类编码****城市编码表**下载
* <p>
* https://lbs.amap.com/api/webservice/download
*/
public static List getPoi(String cityCode, String poiType) throws Exception {
/**
*请求参数释义:
* citylimit: 仅返回指定城市数据 默认false
*
* children: 是否按照层级展示子POI数据 默认0
* 可选值:children=1
* 当为0的时候,子POI都会显示。
* 当为1的时候,子POI会归类到父POI之中。
* 仅在extensions=all的时候生效
* offset: 每页记录数据 默认 20
* 强烈建议不超过25,若超过25可能造成访问报错
* page: 当前页数 1
* 最大翻页数100
* extensions: 返回结果控制 默认 base
* 此项默认返回基本地址信息;取值为all返回地址信息、附近POI、道路以及道路交叉口信息。
*结果释义:
* count:搜索方案数目(最大值为1000) 结果条数
* pois:搜索POI信息列表
* poi:POI信息
* id:唯一id "B023502FH9"
* name:名称 "沙溪服务区"
* type:兴趣点类型:"道路附属设施;服务区;高速服务区"
* address: 地址 "庐江县"
* location: 经纬度 "117.251487,31.1485"
* cityname: 城市名 "合肥市"
* adname: 区域名称 "庐江县"
* photos 照片相关信息 extensions=all 时返回
*/
String url = "https://restapi.amap.com/v3/place/text?parameters?types={}&city={}&page={}&citylimit=true&extensions=all&offset=20&key=" + key;
String jsonBody = "";
Root root = null;
List list = new ArrayList();
for (int i = 1; i < 100; i++) {
jsonBody = HttpUtil.createGet(StrUtil.format(url, poiType, cityCode, i)).execute().body();
root = JSONUtil.toBean(jsonBody, Root.class);
List<Poi> pois = root.getPois();
if (CollUtil.isEmpty(pois)) {
break;
}
list.addAll(pois);
}
return list;
}
POI分类编码 城市编码表下载
三、把高德抓的数据转换为GeoJson格式的矢量数据
1、什么是GeoJson
GeoJSON是一种用于编码各种地理数据结构的格式。
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [125.6, 10.1]
},
"properties": {
"name": "Dinagat Islands"
}
}
以GeoJSON支持以下几何类型:Point,LineString, Polygon,MultiPoint,MultiLineString,和MultiPolygon。具有其他属性的几何对象是Feature对象。要素集包含在FeatureCollection对象中。
参考
说白了就是特定格式的Json。
- 来个体验的网站
GeoJson 在线生成测试地址分享:
http://geojson.io
2、按照GeoJson规范生成即可
我们需要的类型格式是下面这种,只要按照这种格式生成即可;
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"name": "123",
"level": "test"
},
"geometry": {
"type": "Point",
"coordinates": [
113.84033203125,
34.161818161230386
]
}
},
{
"type": "Feature",
"properties": {
"name": "123",
"level": "test"
},
"geometry": {
"type": "Point",
"coordinates": [
117.6416015625,
33.742612777346885
]
}
}
]
}
3、示例代码
static final File geojsonFile = new File("D://test.geojson");
private static void handleToGeoJson(List<Poi> pois) throws IOException {
GeoJson geoJson = new GeoJson();
geoJson.setName("安徽省市、县中心坐标");
geoJson.setType("FeatureCollection");// 勿动
List<Feature> features = new ArrayList<>();
geoJson.setFeatures(features);
pois.forEach(poi ->
{
Feature feature = new Feature();
Map properties = new HashMap();
properties.put("name", poi.getName());
feature.setProperties(properties);
Geometry geometry = new Geometry();
List<Double> coordinates = new ArrayList<>();
List<String> split = StrUtil.split(poi.getLocation(), ',');
double[] doubles = CoordinateTransformUtil.gcj02towgs84(Double.valueOf(split.get(0)), Double.valueOf(split.get(1)));
coordinates.add(doubles[0]);
coordinates.add(doubles[1]);
geometry.setCoordinates(coordinates);
geometry.setType("Point");
feature.setGeometry(geometry);
features.add(feature);
});
String geoJsonString = JSONUtil.toJsonStr(geoJson);
FileWriter writer = new FileWriter(geojsonFile);
writer.write(geoJsonString);
}
4、坐标系转换
因为我的底图是WGS84的,而高德抓取的是GCJ02的坐标系,所以需要转换,转换参考我的文章,有源码
Java精准地图坐标转换 高德 百度 谷歌 腾讯 高德 批量转换工具类达到项目生产精度
四、整体源码
public class GaodeGis {
public static final String key = "用你自己的key";
public static void main(String[] args) throws Exception {
List list = getPoi("340000", "180300");
System.out.println(list.size());
handleToGeoJson(list);
}
/**
* 获取兴趣点,例如交通上常用的服务区,收费站,桥梁,隧道等
*
* @param cityCode 为了您查询的精确,我们强烈建议您使用adcode。
* 安徽省 340000
* 可选值:城市中文、中文全拼、citycode、adcode
* 如:北京/beijing/010/110000
* 填入此参数后,会尽量优先返回此城市数据,但是不一定仅局限此城市结果,若仅需要某个城市数据请调用citylimit参数。
* 如:在深圳市搜*,返回北京*结果。
* @param poiType 查询POI类型,建议分类代码
* 可选值:分类代码 或 汉字(若用汉字,请严格按照附件之中的汉字填写)
* 分类代码由六位数字组成,一共分为三个部分,前两个数字代表大类;中间两个数字代表中类;最后两个数字代表小类。
* 若指定了某个大类,则所属的中类、小类都会被显示。
* 例如:010000为汽车服务(大类)
* 010100为加油站(中类)
* 010101为中国石化(小类)
* 010900为汽车租赁(中类)
* 010901为汽车租赁还车(小类)
* <p>
* **POI分类编码****城市编码表**下载
* <p>
* https://lbs.amap.com/api/webservice/download
*/
public static List getPoi(String cityCode, String poiType) throws Exception {
/**
*请求参数释义:
* citylimit: 仅返回指定城市数据 默认false
*
* children: 是否按照层级展示子POI数据 默认0
* 可选值:children=1
* 当为0的时候,子POI都会显示。
* 当为1的时候,子POI会归类到父POI之中。
* 仅在extensions=all的时候生效
* offset: 每页记录数据 默认 20
* 强烈建议不超过25,若超过25可能造成访问报错
* page: 当前页数 1
* 最大翻页数100
* extensions: 返回结果控制 默认 base
* 此项默认返回基本地址信息;取值为all返回地址信息、附近POI、道路以及道路交叉口信息。
*结果释义:
* count:搜索方案数目(最大值为1000) 结果条数
* pois:搜索POI信息列表
* poi:POI信息
* id:唯一id "B023502FH9"
* name:名称 "沙溪服务区"
* type:兴趣点类型:"道路附属设施;服务区;高速服务区"
* address: 地址 "庐江县"
* location: 经纬度 "117.251487,31.1485"
* cityname: 城市名 "合肥市"
* adname: 区域名称 "庐江县"
* photos 照片相关信息 extensions=all 时返回
*/
String url = "https://restapi.amap.com/v3/place/text?parameters?types={}&city={}&page={}&citylimit=true&extensions=all&offset=20&key=" + key;
String jsonBody = "";
Root root = null;
List list = new ArrayList();
for (int i = 1; i < 100; i++) {
jsonBody = HttpUtil.createGet(StrUtil.format(url, poiType, cityCode, i)).execute().body();
root = JSONUtil.toBean(jsonBody, Root.class);
List<Poi> pois = root.getPois();
if (CollUtil.isEmpty(pois)) {
break;
}
list.addAll(pois);
}
return list;
}
static final File geojsonFile = new File("D://test.geojson");
private static void handleToGeoJson(List<Poi> pois) throws IOException {
GeoJson geoJson = new GeoJson();
geoJson.setName("安徽省市、县中心坐标");
geoJson.setType("FeatureCollection");// 勿动
List<Feature> features = new ArrayList<>();
geoJson.setFeatures(features);
pois.forEach(poi ->
{
Feature feature = new Feature();
Map properties = new HashMap();
properties.put("name", poi.getName());
feature.setProperties(properties);
Geometry geometry = new Geometry();
List<Double> coordinates = new ArrayList<>();
List<String> split = StrUtil.split(poi.getLocation(), ',');
double[] doubles = CoordinateTransformUtil.gcj02towgs84(Double.valueOf(split.get(0)), Double.valueOf(split.get(1)));
coordinates.add(doubles[0]);
coordinates.add(doubles[1]);
geometry.setCoordinates(coordinates);
geometry.setType("Point");
feature.setGeometry(geometry);
features.add(feature);
});
String geoJsonString = JSONUtil.toJsonStr(geoJson);
FileWriter writer = new FileWriter(geojsonFile);
writer.write(geoJsonString);
}
}
总结
老哥们,如果你们因为本文起飞了,请原地全体起立,然后关注一波,加QQ群或者微信一起探讨工作日常和面试相关问题,和大家共同进步。
分享个很好用的免费工具
可以爬省市的矢量数据,以及各大厂商google、百度、高德等的瓦片数据
关注公众号【Java厂面试官】,回复:地图下载器